2016-12-02 2 views
1

인스턴스를 만들 때보 다 클래스를 생성하고 싶습니다. 미리 알려진 시그니처가없는 다양한 수의 함수 참조를 허용합니다. 여기에 거의 내가 원하는 것을 그 예입니다 :알 수없는 서명의 변수 함수 참조를 받아 들일 수있는 클래스

// To show the function refs being used 
void p(int arg) { cout << "int " << arg << endl; } 
void p(string arg) { cout << "string " << arg << endl; } 
void p(int arg1, int arg2) { cout<<"int/int "<<arg1<<arg2<<endl; } 
void p(int arg1, string arg2) { cout<<"int/string "<<arg1<<arg2<<endl; } 

class foo { 
    public: 
    // CTOR takes variadic function refs 
    template <typename... Args> 
    foo(Args... args) { p(args()...); } 
    // "args()..." requires supplied functions to take no parameters 
    // but makes no requirement on their return values. 
}; 

// Using lambdas, but free functions, std::bind(), etc. work too 
foo i([]{return 1;});    // prints "int 1" 
foo s([]{return string("one");}); // prints "string one" 
foo b([]{return 2;}, 
     []{return string("two");}); // prints "int/string 2two" 

내가 인수로 제공되는 기능은 생성자에서 평가되지 않도록이 문제를 해결하는 방법을 볼 수있는 것. p(args()...)에 대한 전화를 나중에 다른 방법으로 foo에 보내고 싶습니다. 이것이 바로 foo가 foo i(1)과 같이 간단하게 생성 될 수없는 이유입니다. 인수 함수를 나중에 호출해야하며 객체가 생성 될 때 한 번만이 아니라 여러 번 호출되어야합니다. 일정한).

이 문제는 나중에 매개 변수에 대한 참조를 저장하는 것과 관련이 있습니다. 클래스가 얼마나 많은 시그니처 또는 그 시그니처를 가질지를 모르는 경우입니다. 어쨌든 인수는 생성자 템플릿뿐만 아니라 클래스 템플릿의 일부가되어야하지만 어떻게해야합니까? 전달 기능을 모두 동일한 서명을 한 경우

, 다음 하나는 비 형태 파라미터를 가지는 클래스 템플릿을 사용하여 템플릿 인수로 기능을 제공 할 수 있습니다 :

template <int (&...Arg)()> 
class bar { 
    public: 
    bar() { p(Arg()...); } 
    other() { p(Arg()...); } // Use in any method 
}; 

int one() { return 1; } 
int two() { return 2; } 
bar<one> bi;  // Prints "int 1" 
bar<one, two> bii; // Prints "int/int 12" 

을하지만이 모든 인수가 기능 할 필요 그 int 반환 및 또한 템플릿 인수가 될 수 없으므로 lambdas 함께 작동하지 않습니다.

+0

:
그것은 최소한의 근로 예를 들어 다음과 같습니다. –

답변

2

람다와 std::function을 사용하면 그렇게 할 수 있습니다.
lambda는 매개 변수 팩을 캡처하고 나중에 압축을 풀 수 있음에 유의하십시오. 내가 이것을 읽고 리스프를 생각

#include<iostream> 
#include<functional> 

void p(int arg) { std::cout << "int " << arg << std::endl; } 
void p(std::string arg) { std::cout << "string " << arg << std::endl; } 
void p(int arg1, int arg2) { std::cout<<"int/int "<<arg1<<arg2<<std::endl; } 
void p(int arg1, std::string arg2) { std::cout<<"int/string "<<arg1<<arg2<<std::endl; } 

class foo { 
public: 
    template <typename... Args> 
    foo(Args... args): func{[args...](){ p(args()...); }} {} 

    void operator()() { func(); } 

private: 
    std::function<void()> func; 
}; 

int main() { 
    // create your objects... 
    foo i([]{return 1;}); 
    foo s([]{return std::string("one");}); 
    foo b([]{return 2;}, []{return std::string("two");}); 
    // ... and use them later 
    i(); 
    s(); 
    b(); 
} 
+0

lambda는 매개 변수 팩에 종속되지 않는 클래스 멤버에 매개 변수 팩을 팩/언팩 할 수 있습니다. – TrentP

+0

내 실제 사용은 더 복잡하며 매개 변수 팩은 함수에 대한 인수의 일부일뿐입니다 (예 : 'make_shared ("name", args() ..., index ++)'람다는'args() ...'부분을 캡처 할 수 없습니다. 이 솔루션은 서명이 매개 변수 팩에 의존하지 않는 완전한 표현식을 생성 할 때까지 람다를 확장하는 것으로 보입니다. '[=] (string n, int i) {return make_shared (n, args() ...})'}와 일치하도록'func'을 조정합니다. – TrentP

+0

@TrentP 음, 답변은 질문에 기반합니다. 나는 진짜 문제가 무엇인지 알 수 없기 때문에, 최선의 해결책은 무엇인지 말할 수 없다. 죄송 해요. – skypjack