带有可变参数模板的元组编译错误
Tuple with Variadic Templates compile error
我正在尝试使用自制的元组实现来学习可变参数模板。
有人可以向我解释为什么以下会导致编译错误吗?
namespace my
{
// Template definition
template <typename... Ts> struct tuple;
template <typename T, typename... Ts>
struct tuple<T, Ts...> : public tuple<Ts...>
{
tuple(T t, Ts... ts) : tuple<Ts...>(ts...), mVal(t) {}
T mVal;
};
template <typename T>
struct tuple<T>
{
tuple(T t) : mVal(t) {}
T mVal;
};
// GetType at an index
template <size_t i, typename... Ts> struct GetType {};
template <size_t i, typename T, typename... Ts>
struct GetType<i, tuple<T,Ts...> >
{
using Type = typename GetType<i-1, tuple<Ts...> >::Type;
};
template <typename T, typename... Ts>
struct GetType<0, tuple<T,Ts...> >
{
using Type = T;
};
template <size_t i, typename... Ts>
typename GetType<i,tuple<Ts...> >::Type Get(tuple<Ts...>& t);
template <size_t i, typename T, typename... Ts>
typename GetType<i,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return Get<i-1, tuple<Ts...> >(t);
}
template <typename T, typename... Ts>
typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return (static_cast<tuple<T, Ts...> >(t)).mVal;
}
}
int main()
{
using myTuple = my::tuple<int, std::string, double, char>;
// The following lines compile fine ....
my::GetType<0,myTuple>::Type s0 = 437;
my::GetType<1,myTuple>::Type s1 = std::string("Test string");
my::GetType<2,myTuple>::Type s2 = 299.3243;
my::GetType<3,myTuple>::Type s3 = 'Z';
std::cout << s0 << " - " << s1 << " - " << s2 << " - " << s3 << std::endl;
myTuple t(437, "This is the actual tuple string", 299.3243, '§');
// This line does not compile !!!
int v = my::Get<0>(t);
return 0;
}
我的意图是指示的行将使用专业化,但查看编译错误很明显没有使用 value=0
的专业化。非常感谢您的帮助。
感谢您的宝贵时间..
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2039: 'Type': is not a member of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): note: see declaration of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): note: see reference to class template instantiation 'my::GetType<18446744073709551615,my::tuple<my::tuple<std::string,double,char>>>' being compiled
..\test.cpp(15): note: see reference to function template instantiation 'int my::Get<0,int,std::string,double,char>(my::tuple<int,std::string,double,char> &)' being compiled
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2061: syntax error: identifier 'Type'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2238: unexpected token(s) preceding ';'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2672: 'Get': no matching overloaded function found
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2770: invalid explicit template argument(s) for 'GetType<i,my::tuple<Ts...>>::Type my::Get(my::tuple<Ts...> &)'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(38): note: see declaration of 'my::Get'
题外话介绍性建议:如果您想使用语言来重新创建您的标准工具版本(std::tuple
,在这种情况下),请避免为您的结构提供相同的名称,类, 函数, 类型...
这可以避免很多强烈的头痛。
建议结束。
据 Daniel Langr 观察,模板函数没有偏特化。
所以只用函数很难得到你想要的
但是structs/classes可以偏特化,所以我建议写一个getH
助手struct
如下
template <std::size_t I, typename T, typename ... Ts>
struct getH
{
static typename GetType<I, tuple<T, Ts...>>::Type
func (tuple<T, Ts...> const & t)
{ return getH<I-1U, Ts...>::func(t); }
};
template <typename T, typename ... Ts>
struct getH<0U, T, Ts...>
{
static T func (tuple<T, Ts...> const & t)
{ return t.mVal; }
};
所以你的Get
可以写成
template <std::size_t I, typename ... Ts>
typename GetType<I, tuple<Ts...>>::Type Get(tuple<Ts...> const & t)
{ return getH<I, Ts...>::func(t); };
如果可以使用 C++14,return 类型可以简化为 auto
而不是 typename GetType<I, tuple<T, Ts...>>::Type
。
我发现在您的代码中,您在不需要时使用了 static_cast
您在 Get<0>
中使用过它
template <typename T, typename... Ts>
typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return (static_cast<tuple<T, Ts...> >(t)).mVal;
}
当 mVal
是 T
类型时(又名 typename GetType<0,tuple<T,Ts...> >::Type
)
我正在尝试使用自制的元组实现来学习可变参数模板。 有人可以向我解释为什么以下会导致编译错误吗?
namespace my
{
// Template definition
template <typename... Ts> struct tuple;
template <typename T, typename... Ts>
struct tuple<T, Ts...> : public tuple<Ts...>
{
tuple(T t, Ts... ts) : tuple<Ts...>(ts...), mVal(t) {}
T mVal;
};
template <typename T>
struct tuple<T>
{
tuple(T t) : mVal(t) {}
T mVal;
};
// GetType at an index
template <size_t i, typename... Ts> struct GetType {};
template <size_t i, typename T, typename... Ts>
struct GetType<i, tuple<T,Ts...> >
{
using Type = typename GetType<i-1, tuple<Ts...> >::Type;
};
template <typename T, typename... Ts>
struct GetType<0, tuple<T,Ts...> >
{
using Type = T;
};
template <size_t i, typename... Ts>
typename GetType<i,tuple<Ts...> >::Type Get(tuple<Ts...>& t);
template <size_t i, typename T, typename... Ts>
typename GetType<i,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return Get<i-1, tuple<Ts...> >(t);
}
template <typename T, typename... Ts>
typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return (static_cast<tuple<T, Ts...> >(t)).mVal;
}
}
int main()
{
using myTuple = my::tuple<int, std::string, double, char>;
// The following lines compile fine ....
my::GetType<0,myTuple>::Type s0 = 437;
my::GetType<1,myTuple>::Type s1 = std::string("Test string");
my::GetType<2,myTuple>::Type s2 = 299.3243;
my::GetType<3,myTuple>::Type s3 = 'Z';
std::cout << s0 << " - " << s1 << " - " << s2 << " - " << s3 << std::endl;
myTuple t(437, "This is the actual tuple string", 299.3243, '§');
// This line does not compile !!!
int v = my::Get<0>(t);
return 0;
}
我的意图是指示的行将使用专业化,但查看编译错误很明显没有使用 value=0
的专业化。非常感谢您的帮助。
感谢您的宝贵时间..
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2039: 'Type': is not a member of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): note: see declaration of 'my::GetType<18446744073709551614,my::tuple<>>'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): note: see reference to class template instantiation 'my::GetType<18446744073709551615,my::tuple<my::tuple<std::string,double,char>>>' being compiled
..\test.cpp(15): note: see reference to function template instantiation 'int my::Get<0,int,std::string,double,char>(my::tuple<int,std::string,double,char> &)' being compiled
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2061: syntax error: identifier 'Type'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(27): error C2238: unexpected token(s) preceding ';'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2672: 'Get': no matching overloaded function found
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(43): error C2770: invalid explicit template argument(s) for 'GetType<i,my::tuple<Ts...>>::Type my::Get(my::tuple<Ts...> &)'
c:\users\praka\workspace\cpp\cpp-tests\recipes\tuple\tuple.h(38): note: see declaration of 'my::Get'
题外话介绍性建议:如果您想使用语言来重新创建您的标准工具版本(std::tuple
,在这种情况下),请避免为您的结构提供相同的名称,类, 函数, 类型...
这可以避免很多强烈的头痛。
建议结束。
据 Daniel Langr 观察,模板函数没有偏特化。
所以只用函数很难得到你想要的
但是structs/classes可以偏特化,所以我建议写一个getH
助手struct
如下
template <std::size_t I, typename T, typename ... Ts>
struct getH
{
static typename GetType<I, tuple<T, Ts...>>::Type
func (tuple<T, Ts...> const & t)
{ return getH<I-1U, Ts...>::func(t); }
};
template <typename T, typename ... Ts>
struct getH<0U, T, Ts...>
{
static T func (tuple<T, Ts...> const & t)
{ return t.mVal; }
};
所以你的Get
可以写成
template <std::size_t I, typename ... Ts>
typename GetType<I, tuple<Ts...>>::Type Get(tuple<Ts...> const & t)
{ return getH<I, Ts...>::func(t); };
如果可以使用 C++14,return 类型可以简化为 auto
而不是 typename GetType<I, tuple<T, Ts...>>::Type
。
我发现在您的代码中,您在不需要时使用了 static_cast
您在 Get<0>
template <typename T, typename... Ts>
typename GetType<0,tuple<T,Ts...> >::Type Get(tuple<T,Ts...>& t)
{
return (static_cast<tuple<T, Ts...> >(t)).mVal;
}
当 mVal
是 T
类型时(又名 typename GetType<0,tuple<T,Ts...> >::Type
)