C++ 多变参数模板未绑定到函数参数
C++ Multiple variadic template not binded to function arguments
我试图使用一些可变模板参数,但很快就被一个我无法理解的错误阻止了。
#include <tuple>
template <typename T>
struct Foo
{
typedef T type;
};
// return a tuple of pair of args and Foo templated on Types
template <typename Head, typename ...Args, typename Type, typename ...Types>
auto func(Head arg, Args... args)
{
return std::tuple_cat(std::make_tuple(std::make_pair(arg, Foo<Type>())),
func<Args..., Types...>(args...));
}
template <typename Head, typename Type>
auto func(Head arg)
{
return std::make_tuple(std::make_pair(arg, Foo<Type>()));
}
int main()
{
func<int, bool, char>(1, 2, 3);
}
这里 func 尝试解压模板参数,并在第二个可变参数模板上创建一个由 func 参数和 Foo 结构模板组成的元组,但我有:
test.cc:25:3: error: no matching function for call to 'func'
func<int, bool, char>(1, 2, 3);
^~~~~~~~~~~~~~~~~~~~~
test.cc:11:6: note: candidate template ignored: couldn't infer template argument 'Type'
auto func(Head arg, Args... args)
^
test.cc:18:6: note: candidate function template not viable: requires single argument 'arg', but 3
arguments were provided
auto func(Head arg)
^
1 error generated.
为什么无法推断类型? (gcc 告诉我同样的)
我确信在看到 std::tuple_cat 实现 (https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a01066_source.html) 之后,多个可变参数模板是可能的,我认为这是一个简单的例子,如果有解决方案或者有人应该比我更了解如果标准不接受这个。
感谢您的帮助,
这里的一个关键数据点是可变参数将与空列表匹配。这会产生几个后果。
第一个结果是给定以下模板声明:
template <typename Head, typename ...Args, typename Type, typename ...Types>
和以下实例化:
<int, bool, char>
实例化匹配模板有几种方式:
1.
Head int
...Args bool
Type char
... Types (empty list)
2.
Head int
...Args (empty list)
Type bool
... Types char
所以,这是歧义的来源之一。 main()
中的引用可以匹配任一模板定义。尽管有各种神秘的规则在某些情况下可以解决这种歧义,但最好不要依赖神秘的模板消歧规则,或者至少不要比使用几种标准的基本 SFINAE
方法更进一步。
但是,回到主题,编译器马上就会落后于 eight-ball,没有明确的候选者来解析 main()
中的模板引用。但情况变得更糟。鉴于
auto func(Head arg, Args... args)
和
auto func(Head arg)
因为可变参数,在本例中是 Args...
,可以匹配空列表,例如:
func(4)
可以匹配任一函数签名。
将所有这些因素结合在一起,编译器无法在这里真正做出正面或反面。
将推导的参数放在最后。
...
模板参数是贪婪的——它们将消耗传入的参数并且不会 "save" 任何用于以后的模板参数。
完成后,从 non-template 个函数参数中进行推导。
这样交换:
template <typename Type, typename ...Types, typename Head, typename ...Args>
auto func(Head arg, Args... args)
此外,去掉 other 重载,所以 func<int,int>(3)
没有歧义。
这会导致递归中断,但这很容易修复:
template <class... Types, class... Args>
auto func(Args... args)
{
return std::make_tuple(std::make_pair(args, Foo<Types>())...);
}
它的好处是又好又矮。
我试图使用一些可变模板参数,但很快就被一个我无法理解的错误阻止了。
#include <tuple>
template <typename T>
struct Foo
{
typedef T type;
};
// return a tuple of pair of args and Foo templated on Types
template <typename Head, typename ...Args, typename Type, typename ...Types>
auto func(Head arg, Args... args)
{
return std::tuple_cat(std::make_tuple(std::make_pair(arg, Foo<Type>())),
func<Args..., Types...>(args...));
}
template <typename Head, typename Type>
auto func(Head arg)
{
return std::make_tuple(std::make_pair(arg, Foo<Type>()));
}
int main()
{
func<int, bool, char>(1, 2, 3);
}
这里 func 尝试解压模板参数,并在第二个可变参数模板上创建一个由 func 参数和 Foo 结构模板组成的元组,但我有:
test.cc:25:3: error: no matching function for call to 'func'
func<int, bool, char>(1, 2, 3);
^~~~~~~~~~~~~~~~~~~~~
test.cc:11:6: note: candidate template ignored: couldn't infer template argument 'Type'
auto func(Head arg, Args... args)
^
test.cc:18:6: note: candidate function template not viable: requires single argument 'arg', but 3
arguments were provided
auto func(Head arg)
^
1 error generated.
为什么无法推断类型? (gcc 告诉我同样的)
我确信在看到 std::tuple_cat 实现 (https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a01066_source.html) 之后,多个可变参数模板是可能的,我认为这是一个简单的例子,如果有解决方案或者有人应该比我更了解如果标准不接受这个。
感谢您的帮助,
这里的一个关键数据点是可变参数将与空列表匹配。这会产生几个后果。
第一个结果是给定以下模板声明:
template <typename Head, typename ...Args, typename Type, typename ...Types>
和以下实例化:
<int, bool, char>
实例化匹配模板有几种方式:
1.
Head int
...Args bool
Type char
... Types (empty list)
2.
Head int
...Args (empty list)
Type bool
... Types char
所以,这是歧义的来源之一。 main()
中的引用可以匹配任一模板定义。尽管有各种神秘的规则在某些情况下可以解决这种歧义,但最好不要依赖神秘的模板消歧规则,或者至少不要比使用几种标准的基本 SFINAE
方法更进一步。
但是,回到主题,编译器马上就会落后于 eight-ball,没有明确的候选者来解析 main()
中的模板引用。但情况变得更糟。鉴于
auto func(Head arg, Args... args)
和
auto func(Head arg)
因为可变参数,在本例中是 Args...
,可以匹配空列表,例如:
func(4)
可以匹配任一函数签名。
将所有这些因素结合在一起,编译器无法在这里真正做出正面或反面。
将推导的参数放在最后。
...
模板参数是贪婪的——它们将消耗传入的参数并且不会 "save" 任何用于以后的模板参数。
完成后,从 non-template 个函数参数中进行推导。
这样交换:
template <typename Type, typename ...Types, typename Head, typename ...Args>
auto func(Head arg, Args... args)
此外,去掉 other 重载,所以 func<int,int>(3)
没有歧义。
这会导致递归中断,但这很容易修复:
template <class... Types, class... Args>
auto func(Args... args)
{
return std::make_tuple(std::make_pair(args, Foo<Types>())...);
}
它的好处是又好又矮。