2017-11-16 14 views
3

이 의사 조각을 고려 클래스의 구성원으로 일반적인 표준 : 기능을 가진 일반 람다 :C++ 14 :

class SomeClass 
{ 
public: 
    SomeClass() 
    { 
     if(true) 
     { 
      fooCall = [](auto a){ cout << a.sayHello(); }; 
     } 
     else 
     { 
      fooCall = [](auto b){ cout << b.sayHello(); }; 
     } 
    } 
private: 
    template<typename T> 
    std::function<void(T)> fooCall; 
}; 

내가 원하는 차례에 일반적인 람다를 저장하는 클래스 멤버 fooCall입니다 생성자에 할당됩니다.

fooCall은 템플릿 데이터 멤버가 될 수 없다는 컴파일러의 불만이 있습니다.

클래스에 일반 람다를 저장하는 방법에 대한 간단한 해결책이 있습니까?

+1

불행히도 간단한 해결책이 없습니다. 일반적인 lambda가 templatized 함수와 같다고 생각해보십시오. 아직 인스턴스화되지 않았기 때문에 주소를 가져올 수 없습니다. 구체적인 사용 사례에 대해 더 많이 알아야합니다. 아마도 작은 워크 플로로 OP를 육체로 만들 수 있을까요? – AndyG

+0

해결하려는 실제 문제는 무엇입니까? – Barry

+0

클래스의 멤버로 일반 람다를 저장할 수 없었지만 클래스 생성자 내에서 호출을 호출 할 수있었습니다. –

답변

2

유형 지우는 구체적인 서명이 없으므로 실행시 두 가지 일반 람다 중에서 하나를 선택할 수는 없습니다.

당신이 컴파일 타임에 결정을 내릴 수 있다면, 당신은 클래스 자체 템플리트화할 수 있습니다

template <typename F> 
class SomeClass 
{ 
private: 
    F fooCall; 

public: 
    SomeClass(F&& f) : fooCall{std::move(f)} { } 
}; 

당신은 다음 F을 추론하는 도우미 함수를 만들 수 있습니다

auto makeSomeClassImpl(std::true_type) 
{ 
    auto l = [](auto a){ cout << a.sayHello(); }; 
    return SomeClass<decltype(l)>{std::move(l)}; 
} 

auto makeSomeClassImpl(std::false_type) 
{ 
    auto l = [](auto b){ cout << b.sayHello(); }; 
    return SomeClass<decltype(l)>{std::move(l)}; 
} 

template <bool B> 
auto makeSomeClass() 
{ 
    return makeSomeClassImpl(std::bool_constant<B>{}); 
} 
+0

Thx이지만 조건은 런타임에만 사용할 수 있습니다 .-( – juxeii

+0

@juxeii :이를 반영하여 영업 이익을 업데이트하십시오. 작동하려면 작동 방식을 지워야합니다. – AndyG

1

내가 아니었다를 클래스에서 std::function<>generic lambda으로 직접 저장할 수 있습니다 (member). 내가 할 수 있었던 것은 특별히 클래스의 생성자 내에서 하나를 사용하는 것이 었습니다. 나는 이것이 OP가 달성하려고 시도한 것이라면 100 % 확실하지는 않지만 이것은 컴파일 할 수 있었고, & 빌드는 OP가 그들이 제공 한 코드에 의해 목표로 삼고있는 것으로 의심하고 있습니다. 적절한 헤더와

template<class> 
class test { 
public: // While testing I changed this to public access... 
     // Could not get object below to compile, build & run 
    /*template<class U = T> 
    static std::function<void(U)> fooCall;*/ 
public: 
    test(); 
}; 

template<class T> 
test<T>::test() { 
    // This would not compile, build & run 
    // fooCall<T> = [](T t) { std::cout << t.sayHello(); }; 

    // Removed the variable within the class as a member and moved it here 
    // to local scope of the class's constructor 
    std::function<void(T)> fooCall = [](auto a) { std::cout << a.sayHello(); }; 
    T t; // created an instance of <Type T> 
    fooCall(t); // passed t into fooCall's constructor to invoke the call. 
} 

struct A { 
    std::string sayHello() { return "A say's Hello!\n"; } 
}; 

struct B { 
    std::string sayHello() { return "B say's Hello!\n"; } 
}; 


int main() { 
    // could not instantiate an object of SomeClass<T> with a member of 
    // a std::function<> type that is stored by a type of a generic lambda. 

    /*SomeClass<A> someA; 
    SomeClass<B> someB; 
    someA.foo(); 
    someB.foo();*/ 

    // Simply just used the object's constructors to invoke the locally stored lambda within the class's constructor. 
    test<A> a; 
    test<B> b; 

    std::cout << "\nPress any key & enter to quit." << std::endl; 
    char c; 
    std::cin >> c; 

    return 0; 
} 

위, 컴파일 (7 64 비트했던 Windows에서 적어도 MSVS 2017 년) & 실행 아래의 출력을 제공 구축해야한다대로; 나는 오류가있는 곳에 주석을 달고 작업 예제를 달성하기 위해 여러 가지 기술을 시도했다. 다른 제안이있을 때 오류가 발생했고 위의 코드로 작업하는 동안 더 많은 것을 발견했다. 내가 컴파일하고, 빌드하고, 실행할 수 있었던 것은이 간단한 코드로 주석없이 내려왔다. 나는 또한 모든 유형의 작동 보여주는 또 다른 간단한 클래스를 추가 :

template<class> 
class test { 
public: 
    test(); 
}; 

template<class T> 
test<T>::test() { 
    std::function<void(T)> fooCall = [](auto a) { std::cout << a.sayHello(); }; 
    T t; 
    fooCall(t); 
} 

struct A { 
    std::string sayHello() { return "A say's Hello!\n"; } 
}; 

struct B { 
    std::string sayHello() { return "B say's Hello!\n"; } 
}; 

struct C {  
    int sayHello() { return 100; } 
}; 

int main() { 
    test<A> testA; 
    test<B> testB; 
    test<C> testC; 

    std::cout << "\nPress any key & enter to quit." << std::endl; 
    char c; 
    std::cin >> c; 

    return 0; 
} 

출력 :

A say's Hello! 
B say's Hello! 
100 

Press any key & enter to quit 

이 직접 또는 간접적 여부하지만 경우 OP 도움이 될 것입니다 경우 모르겠어요 그렇지 않더라도 여전히 그들이 돌아와서 쌓아 올릴 수있는 어떤 것입니다.