2016-11-10 55 views
3

是否可以將變量函數應用於std :: apply的元組?應用std :: apply的變量函數:: apply

例如,下面的代碼工作正常GCC 6.2.1:

void print_t(std::string i, std::string j) { 
    std::cout << i << " " << j << std::endl; 
} 

int main() { 
     std::tuple<std::string, std::string> t{"ab", "cd"}; 
     std::experimental::apply(print_t, t); 
     return 0; 
} 

但是,如果我嘗試應用可變參數函數:

template<typename T> 
void vprint(T && t) { 
    std::cout << std::forward<T>(t) << std::endl; 
} 

template<typename T, typename ... Ts> 
void vprint(T && t, Ts ... ts) { 
    std::cout << std::forward<T>(t) << " "; 
    vprint<Ts...>(std::forward<Ts>(ts)...); 
} 

int main() { 
     std::tuple<std::string, std::string> t{"fd", "ab"}; 
     std::experimental::apply(vprint, t); 
     return 0; 
} 

編譯器抱怨說,它不能推導出模板參數vprint。好吧,讓我們明確地寫出它們:

std::experimental::apply(vprint<std::string, std::string>, t); 

現在,編譯器結束了一些暴露標準庫內部的模糊錯誤。

我在C++ 11中編寫了自己的std::apply實現,並且我理解爲什麼它不能推導出可變參數函數模板的參數。但是,理論上std::apply具有所有扣除所需的信息。

那麼,可變參數函數在GCC6中的應用還沒有實現? C++ 17兼容的編譯器是否允許這樣的應用程序? 如果不是,他們會允許應用實例化的可變參數模板函數,如vprint<std::string, std::string>

回答

6

隨着vprint<std::string, std::string>,你必須通過R值引用,所以

std::experimental::apply(vprint<std::string, std::string>, std::move(t)); 

更好的辦法是使用仿函數(感謝通用拉姆達):

std::experimental::apply([](auto&&... args) { 
          vprint(std::forward<decltype(args)>(args)...); 
         }, 
         t); 
+0

爲什麼是第二方案更好? 'std :: move'基本上是對右值引用的強制轉換,所以這兩個代碼片段的語義看起來都是相同的。 – Sergey

+0

@Sergey:第二個繼續轉發參數,而第一個強制知道元組類型,可能會修改't'(因爲print_t通過複製傳遞)。 – Jarod42

+2

@Sergey我們假設'print_t'不是您想要調用的唯一函數;並且'std :: string &&'參數可以自由移動。你不會在你的實現中移動它。從語義上講,在移入函數調用之後,沒有人應該依賴'std :: string',但是,除非有強有力的保證(比如'get'提供)。 – Yakk