2017-10-31 1 views
2

이 질문은 this, this 및 잠재적으로 this과 관련됩니다.함수 기호에 따라 값/참조로 가변 템플릿의 전달 유형

class Processes { 
public: 
    Processes() {} 

    ~Processes() { 
    for (auto &t : threads_) { 
     t.join(); 
    } 
    } 

    template <class Function, typename... Args> 
    void AddFunction(Function &&func, Args &&... args) { 
    threads_.emplace_back(std::forward<Function>(func), 
          std::forward<Args>(args)...); 
    } 

private: 
    std::vector<std::thread> threads_; 
} 

이 결과 :

난 후 전달 인자는 전달 함수를 호출 std::thread 급부상 상기 AddFunction 방법은 함수 및 그 함수의 인수의 목록을 수신하는 다음의 클래스를 가질은이 객체가 스레드의 수명을 초과 할 것을 보장하기 위해 에 std::ref으로 래핑 된 참조를 필요로하고, 그렇지 않으면 복사 할 것이기 때문에 객체가 복사 불가능한 경우 실패합니다.

대상 함수 서명에 지정된 경우 참조로 개체를 전달하려고합니다.

나는 람다 사용하여 시도 :

template <class Function, typename... Args> 
void AddFunction(Function &&func, Args &&... args) { 
    threads_.emplace_back([&]() { func(std::forward<Args>(args)...); }); 
} 

을하지만 람다는 참조 동작에 의해 캡처 결과 값을 전달하기 전에 참조로 값을 캡처로 이것은 잘못된 동작을 초래한다.

대상 함수 시그니처에 따라 인수를 값 또는 참조로 전달하는 함수를 구현하려면 어떻게합니까? ?


예 : 당신은 함수 서명이 변경 될 수 있습니다

void Foo(int a, std::vector<int> const &b) { /* ... */ } 

int main() { 
    Processes procs; 
    int a = 6; 
    std::vector<int> b; 
    procs.AddFunction(
    Foo, 
    a, // Should be passed by value 
    b // Should be passed by reference (as implemented by std::ref) 
); 
    return 0; 
} 

답변

1

덜 일반적인 될 수 있습니다 :

우선 몇 가지 헬퍼 : 다음

template <typename T> struct non_deducible { using type = T; }; 
template <typename T> using non_deducible_t = typename non_deducible<T>::type; 

template <typename T> 
auto passed_by(T& t, std::true_type) 
{ 
    return std::ref(t); 
} 

template <typename T> 
T&& passed_by(T&& t, std::false_type) 
{ 
    return std::forward<T>(t); 
} 

그리고

우변가 폐쇄로 이동하고 lvalues ​​ 참조로 촬영하는 것을 의미 - 당신은 람다 경로를 아래로 이동하려면
template <class Ret, typename... Args> 
void AddFunction(Ret (*func)(Args...), non_deducible_t<Args>... args) { 
    threads_.emplace_back(func, 
          passed_by(std::forward<Args>(args), 
            std::is_reference<Args>{})...); 
} 
+0

는이 문제를 해결했다. 이런 식으로 함수 호출을 풀 수 있다는 것을 몰랐습니다. '{} '구문은 무엇입니까? 그것은 단지 빈 생성자입니까? 고맙습니다! – jlicht

+0

예,'type {}'은'type'의 비어있는 생성자입니다.'{}'구문을 사용하면'type()'과 반대되는 경우에 구문 분석을 피할 수 있습니다. – Jarod42

2

, 당신은 allow you to capture by "perfect-forward"이 몇 가지 유틸리티를 구현할 수 있습니다. 당신은 T 또는 T&이 (내 링크 된 문서에서는 청소기 구현이)를 저장하는 중 std::tuple<T>를 사용할 수 있습니다

template <class Function, typename... Args> 
void AddFunction(Function &&func, Args &&... args) 
{ 
    threads_.emplace_back([ 
     targs = std::tuple<Args...>{std::forward<Args>(args)...}, 
     tfunc = std::tuple<Function>(func)]() mutable 
    { 
     std::apply([&targs](auto&& x_func) 
     { 
      std::apply([&x_func](auto&&... x_args) 
      { 
       std::forward<Function>(x_func)(
        std::forward<Args>(x_args)... 
       ); 
      }, targs); 
     }, tfunc); 
    }); 
} 

live wandbox example