以下代码是递归变量函数重载的教科书示例。在clang和GCC中,它编译干净,main
返回36(如预期的那样):
template <typename T>
int add(T val)
{
return val;
}
template <typename FirstTypeT, typename... RestT>
int add(FirstTypeT first_value, RestT... rest)
{
return first_value + add<RestT...>(rest...);
}
int main(void)
{
return add(12, 12, 12);
}
然而,这里有一个小小的修改。它在模板定义中使用依赖类型,而不是直接使用模板参数:
struct Foo
{
using SomeType = int;
};
template <typename T>
int add(typename T::SomeType val)
{
return val;
}
template <typename FirstT, typename... RestT>
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
{
return first_value + add<RestT...>(rest...);
}
int main(void)
{
return add<Foo, Foo, Foo>(12, 12, 12);
}
它使用GCC 5.2编译并运行,但使用clang 3.8时失败:
clang++ variadic.cpp -o var -std=c++11 -Wall
variadic.cpp:15:26: error: call to 'add' is ambiguous
return first_value + add<RestT...>(rest...);
^~~~~~~~~~~~~
variadic.cpp:15:26: note: in instantiation of function template specialization 'add<Foo, Foo>' requested here
return first_value + add<RestT...>(rest...);
^
variadic.cpp:20:12: note: in instantiation of function template specialization 'add<Foo, Foo, Foo>' requested here
return add<Foo, Foo, Foo>(12, 12, 12);
^
variadic.cpp:7:5: note: candidate function [with T = Foo]
int add(typename T::SomeType val)
^
variadic.cpp:13:5: note: candidate function [with FirstT = Foo, RestT = <>]
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
^
1 error generated.
我的问题是双重的。
typename RestT::SomeType...
?RestT = 实例化
错误消息已经显示了原因。
当生成add(12)时,有两个可用的模板函数。那是
template <typename T>
int add(typename T::SomeType val);
和
template <typename FirstT, typename... RestT>
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest);
// and RestT is empty here(RestT = <>)
这不是标准用法,叮当是正确的。
请考虑此代码。
#include <tuple>
#include <type_traits>
struct Foo
{
using SomeType = int;
};
// helper function to sum a tuple of any size
template<typename Tuple, std::size_t N>
struct TupleSum {
typedef typename std::tuple_element<N - 1, Tuple>::type ref_t;
typedef typename std::remove_reference<ref_t>::type noref_t;
static noref_t sum(const Tuple& t)
{
return std::get<N - 1>(t) + TupleSum<Tuple, N - 1>::sum(t);
}
};
template<typename Tuple>
struct TupleSum<Tuple, 1> {
typedef typename std::tuple_element<0, Tuple>::type ref_t;
typedef typename std::remove_reference<ref_t>::type noref_t;
static noref_t sum(const Tuple& t)
{
return std::get<0>(t);
}
};
template <typename... RestT>
int add(typename RestT::SomeType... rest) {
typedef decltype(std::forward_as_tuple(rest...)) tuple_t;
return TupleSum<tuple_t, sizeof...(RestT) >::sum(std::forward_as_tuple(rest...));
}
int main(void)
{
return add<Foo, Foo, Foo>(12, 12, 12);
}
> < li >是的,很好。 < li>
当前的措辞在这一点上非常明确:在部分订购期间,参数包被完全忽略,因为它没有任何参数([temp.deduct.partial]/(3.1))。[temp.func.order]/5也给出了一个非常中肯的例子,即使有可推导的模板参数——表明你的第一个例子也是模棱两可的:
[注意:由于调用上下文中的部分排序只考虑有显式调用参数的参数,因此某些参数会被忽略(即函数参数包、带默认参数的参数和省略号参数)。[...] [例如:
template<class T, class... U> void f(T, U ...); // #1
template<class T > void f(T ); // #2
void h(int i) {
f(&i); // error: ambiguous
// [...]
}
然而,这不是最佳的。关于变量模板偏序有一个核心问题1395:
CWG同意这个例子应该被接受,把这个例子作为最后的决胜局来处理,比起一个参数包,他更喜欢一个省略的参数。
(第1825期给出了一个更精细的策略。两个编译器都为第一种情况实现此规则;只有海湾合作委员会对第二个(即可以被认为是领先半步)。
在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty
我希望维护语法,但似乎只能将typenames放在括号中,而不能将类放在括号中。以下是我当前的代码: 问题1:我找不到一种方法来使“default”参数对于特殊化不是必需的。我尝试了使用默认构造函数的代理类,将第三个参数更改为指针,并指定nullptr(这在语法上并不理想)和对类型的常量引用(这仍然需要用户端的三个参数),但似乎没有任何东西允许在中接受两个参数。 问题2:我找不到正确的语法来获得混
请考虑以下定义和演绎指南: 如果我尝试使用显式模板参数实例化 ,代码将正确编译: 如果我试图通过演绎指南实例化< code>foo... > G7产生编译器错误: clang 5 爆炸: wandbox上的实例 虽然clang肯定被窃听了(报告为问题#32673),但g拒绝我的代码是正确的吗?我的代码格式错误吗?
通常我知道如何修复不明确的类型变量问题,但这次我不知道了。长话短说,我使用protobuf Haskell库来处理协议缓冲区。该库使您忘记了单独维护。proto文件,如果数据类型分别是Encode和Decode类型类的实例,则派生序列化和反序列化数据类型的方法。 我正在protobuf之上设计一个简单的协议。有一个主消息数据类型,包含消息id、消息类型和一些取决于类型的可选数据。我想有一个函数来获
OpenGL定义了C函数来管理资源。我编写了一个简单的包装器来以RAII的方式处理它们。函数对类似于和。但是,也有一些函数对适用于资源数组,例如和。对于前者,我编写了一个简单的类来完成这项工作,对于后者,我编写了另一个处理数组的类。然而,我注意到有时我只使用一个缓冲区或纹理,在那里我不必承担向量的费用,我想如果发布函数在开始时采用大小参数,我会专门化类析构函数,但是... 对于上述SSCCE g树
我对编程和C++相当陌生。我有一个函数,我想接受以模板化值作为参数的函数指针。我的意思是... 我有这个功能: 我试过的: 结果: .h:165:22:注意:已忽略候选模板:无法将“function ,allocator >&)”与“void(*)(bool,std::vectorstd::vectorstd::allocatorstd::tuple &)”void postgrescaller: