请考虑以下代码:
#include <iostream> #include <functional> template<typename... Args> void testfunc(const std::function<void (float,Args...,char)>& func) { } int main(int argc,char* argv[]) { auto func = [](float,int,char) {}; auto sfunc = static_cast<std::function<void (float,char)>>(func); testfunc<int>(sfunc); return 0; }
我明确指定了类型,因为(https://stackoverflow.com/a/40476083):
When a parameter pack doesn’t appear last in the parameter
declaration,it is a non-deduced context. A non-deduced context means
that the template arguments have to be given explicitly.
MSVC成功编译它,而gcc和clang都拒绝代码:
source_file.cpp: In function ‘int main(int,char**)’: source_file.cpp:14:24: error: no matching function for call to ‘testfunc(std::function<void(float,char)>&)’ testfunc<int>(sfunc); ^ source_file.cpp:5:6: note: candidate: template<class ... Args> void testfunc(const std::function<void(float,Args ...,char)>&) void testfunc(const std::function<void (float,char)>& func) ^ source_file.cpp:5:6: note: template argument deduction/substitution Failed: source_file.cpp:14:24: note: mismatched types ‘char’ and ‘int’ testfunc<int>(sfunc); ^ source_file.cpp:14:24: note: ‘std::function<void(float,char)>’ is not derived from ‘const std::function<void(float,char)>’
现在让我们稍作改动 – 让我们从本地func中删除int参数,从而导致模板参数包变空:
#include <iostream> #include <functional> template<typename... Args> void testfunc(const std::function<void (float,char)>>(func); testfunc<>(sfunc); return 0; }
这一次,所有三个编译器都拒绝代码不正确.
使用http://rextester.com/l/cpp_online_compiler_gcc和本地Visual Studio安装进行测试.
问题:
>第一种情况谁是正确的?
>如何实现预期效果 – 即,如何明确指定(可能为空)参数包?
解决方法
我们可以阻止扣除:
template<typename... Args> void testfunc(const block_deduction<std::function<void (float,char)>>& func)
同
template<class T> struct tag_t{using type=T;}; template<class T> using block_deduction=typename tag_t<T>::type;
现在Args ……处于非演绎的背景中.
你可以用SFINAE做更好的事情并省略char然后在Args的末尾测试char,但这看起来有点过分.
当gcc和clang不同意MSVC时,我会向甜甜圈打赌,MSVC不对.但我没有标准钻探确认.