请考虑以下代码:
- #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不对.但我没有标准钻探确认.