问题描述
考虑以下代码:
#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, int, char)>>(func);
testfunc<int>(sfunc);
return 0;
}
我明确指定类型是因为( https://stackoverflow.com/a/40476083 ):
I specify the type explicitly because (https://stackoverflow.com/a/40476083):
MSVC成功编译了它,而gcc和clang都拒绝了该代码:
MSVC successfully compiles it, while both gcc and clang reject the code:
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, int, 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, Args..., 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, int, char)>’ is not derived from ‘const std::function<void(float, Args ..., char)>’
现在让我们稍作更改-让我们从本地 func
中删除 int
参数,从而使模板参数包变为空:
Let's now make a slight change - let's remove the int
argument from our local func
, thereby causing the template argument pack to become empty:
#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, char) {};
auto sfunc = static_cast<std::function<void (float, char)>>(func);
testfunc<>(sfunc);
return 0;
}
这一次,所有三个编译器都将代码视为错误.已通过 http://rextester.com/l/cpp_online_compiler_gcc 和本地Visual Studio安装进行了测试.
This time, all three compilers reject the code as incorrect.Tested with http://rextester.com/l/cpp_online_compiler_gcc and a local Visual Studio installation.
问题:
- 在第一种情况下谁是正确的?
- 如何达到理想的效果-即如何明确指定(可能为空)参数包?
推荐答案
我们可以阻止推论:
template<typename... Args>
void testfunc(const block_deduction<std::function<void (float, Args..., char)>>& func)
使用
template<class T>
struct tag_t{using type=T;};
template<class T>
using block_deduction=typename tag_t<T>::type;
现在是 Args ...
处于非推论上下文中.
and now Args...
is in a non-deduced context.
您可以使用SFINAE进行更奇特的操作,并省略 char
,然后测试 char
在 Args ...
的末尾,但是似乎太过分了.
You can do fancier things with SFINAE and omitting char
then testing that char
is at the end of the Args...
, but that seems overkill.
当gcc和clang与MSVC意见不一致时,我会向甜甜圈下注,这是不对的.但是我没有标准地去证实这一点.
I will bet dollars to donuts that when gcc and clang disagree with MSVC, MSVC isn't right. But I have not standard delved to confirm that.
这篇关于未作为最后一个参数传递时的模板参数包扣除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!