C++ - 如何调用递归继承的模板化基的模板化方法 class
C++ - How to call a templated method of a recursively inherited templated base class
我正在尝试创建一个 Tuple
class,其中包含使用可变参数模板的任意类型的任意数量的条目,并且能够通过模板化获得第 n
个条目entry
方法,所以我可以按如下方式使用它:
Tuple<int, int, std::string, double> t(1, 2, "Hello World", 3.4);
std::cout << t.entry<1>() << std::endl; // Prints 2
std::cout << t.entry<2>() << std::endl; // Prints "Hello World"
我目前的做法:
template<typename ...Types>
struct Tuple;
template<typename Type>
struct Tuple<Type>
{
Tuple(Type value) : value(value) { };
Type value;
template<int Index>
Type& entry()
{
return value;
}
};
template<typename Type, typename... Types>
struct Tuple<Type, Types...> : public Tuple<Types...>
{
Tuple(Type value, Types ...args) : Tuple<Types...>(args...), value(value) { }
Type value;
template<int Index>
auto entry() -> decltype(Tuple<Types...>::entry<Index-1>())&
{
return Tuple<Types...>::entry<Index-1>();
}
template<>
Type& entry<0>()
{
return value;
}
};
第一个结构为一个元素提供“基本”情况,第二个结构递归地建立在它的基础上。但是,我收到错误
In member function ‘decltype (((Tuple<Types ...>::entry < (Index - 1)) > <expression error>))& Tuple<Type, Types ...>::entry()’:
error: expected primary-expression before ‘)’ token
如何调用模板化基础的模板化方法class?
你需要在::entry
前加一个template
template<int Index> // ...................VVVVVVVVV
auto entry() -> decltype(Tuple<Types...>::template entry<Index-1>())&
{ // .......................VVVVVVVVV
return Tuple<Types...>::template entry<Index-1>();
}
或::entry
后的<
被解析为关系运算符
但是你还有一个问题:entry()
的特化:
template<>
Type& entry<0>()
{
return value;
}
不幸的是,如果不专门化包含 class.
的方法,则无法专门化方法
如果可以编译C++17,就可以避免方法特化而使用if constexpr
template <int Index>
auto & entry()
{
if constexpr ( Index == 0 )
return value;
else
return Tuple<Types...>::template entry<Index-1>();
}
Pre C++17 在 C++14 中...我想你可以使用标签调度来解决
template <int>
Type & entry_helper (std::true_type)
{ return value; }
template <int Index>
auto & entry_helper (std::false_type)
{ return Tuple<Types...>::template entry<Index-1>(); }
template <int Index>
auto & entry()
{ return entry_helper<Index>(std::integral_constant<bool, Index==0>{}); }
在 C++11 中,对于 entry()
和第二个 entry_helper()
[=28,您还需要输入尾随 return =]
正如 Patrick Roberts 所指出的(谢谢!)解决方案,添加尾随 return 类型,适用于带有 g++ 的 C++11 但不适用于 clang++,用于检测 return 的问题在递归上下文中键入。
对于 C++11,我提出了一个完全不同的解决方案,它避免了 entry()
/entry_helper()
递归,但在 class 级别添加了另一个间接级别(添加递归基础 class 结构 Tpl
)。还为 entry()
和 entry_helper()
添加完美转发、无符号索引和常量版本。
#include <utility>
#include <iostream>
#include <type_traits>
template <std::size_t, typename...>
struct Tpl
{ void entry_helper () {} };
template <std::size_t I, typename T, typename ... Ts>
struct Tpl<I, T, Ts...> : public Tpl<I+1u, Ts...>
{
using Tpl<I+1, Ts...>::entry_helper;
Tpl (T && t, Ts && ... ts)
: Tpl<I+1u, Ts...>{std::forward<Ts>(ts)...}, value{std::forward<T>(t)}
{ }
T value;
T & entry_helper (std::integral_constant<std::size_t, I>)
{ return value; }
T const & entry_helper (std::integral_constant<std::size_t, I>) const
{ return value; }
};
template <typename ... Ts>
struct Tuple : public Tpl<0, Ts...>
{
using Tpl<0, Ts...>::entry_helper;
Tuple (Ts && ... ts) : Tpl<0u, Ts...>{std::forward<Ts>(ts)...}
{ }
template <std::size_t I>
auto entry ()
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
template <std::size_t I>
auto entry () const
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) const &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
};
int main()
{
Tuple<int, int, std::string, double> t(1, 2, "Hello World", 3.4);
std::cout << t.entry<1>() << std::endl; // Prints 2
std::cout << t.entry<2>() << std::endl; // Prints "Hello World"
}
假设您至少使用 C++14,您可以使用 auto&
instead of a trailing return type, and as pointed out by 您需要在语法中的成员函数调用之前添加 template
关键字。
您还可以简化您的定义,因为您只需要一个空基 class,而不是为一种类型实现特化的 class;您的第二个 class 已经为一种类型实现了必要的行为。如果您使用的是 C++17
,则此简化要求您使用 std::enable_if
, or if constexpr
重写 entry()
// only needed for C++14 when using std::enable_if
#include <type_traits>
template<typename...>
struct Tuple
{
};
template<typename T, typename... Ts>
struct Tuple<T, Ts...> : public Tuple<Ts...>
{
Tuple(T value, Ts ...args) : value(value), Tuple<Ts...>(args...) { }
T value;
template<std::size_t I, std::enable_if_t<I == 0, bool> = true>
T& entry() { return value; }
template<std::size_t I, std::enable_if_t<I != 0, bool> = true>
auto& entry() { return Tuple<Ts...>::template entry<I - 1>(); }
// // requires C++17 support
// template<std::size_t I>
// auto& entry() {
// if constexpr (I == 0) { return value; }
// else { return Tuple<Ts...>::template entry<I - 1>(); }
// }
};
上试用
我正在尝试创建一个 Tuple
class,其中包含使用可变参数模板的任意类型的任意数量的条目,并且能够通过模板化获得第 n
个条目entry
方法,所以我可以按如下方式使用它:
Tuple<int, int, std::string, double> t(1, 2, "Hello World", 3.4);
std::cout << t.entry<1>() << std::endl; // Prints 2
std::cout << t.entry<2>() << std::endl; // Prints "Hello World"
我目前的做法:
template<typename ...Types>
struct Tuple;
template<typename Type>
struct Tuple<Type>
{
Tuple(Type value) : value(value) { };
Type value;
template<int Index>
Type& entry()
{
return value;
}
};
template<typename Type, typename... Types>
struct Tuple<Type, Types...> : public Tuple<Types...>
{
Tuple(Type value, Types ...args) : Tuple<Types...>(args...), value(value) { }
Type value;
template<int Index>
auto entry() -> decltype(Tuple<Types...>::entry<Index-1>())&
{
return Tuple<Types...>::entry<Index-1>();
}
template<>
Type& entry<0>()
{
return value;
}
};
第一个结构为一个元素提供“基本”情况,第二个结构递归地建立在它的基础上。但是,我收到错误
In member function ‘decltype (((Tuple<Types ...>::entry < (Index - 1)) > <expression error>))& Tuple<Type, Types ...>::entry()’:
error: expected primary-expression before ‘)’ token
如何调用模板化基础的模板化方法class?
你需要在::entry
template
template<int Index> // ...................VVVVVVVVV
auto entry() -> decltype(Tuple<Types...>::template entry<Index-1>())&
{ // .......................VVVVVVVVV
return Tuple<Types...>::template entry<Index-1>();
}
或::entry
后的<
被解析为关系运算符
但是你还有一个问题:entry()
的特化:
template<>
Type& entry<0>()
{
return value;
}
不幸的是,如果不专门化包含 class.
的方法,则无法专门化方法如果可以编译C++17,就可以避免方法特化而使用if constexpr
template <int Index>
auto & entry()
{
if constexpr ( Index == 0 )
return value;
else
return Tuple<Types...>::template entry<Index-1>();
}
Pre C++17 在 C++14 中...我想你可以使用标签调度来解决
template <int>
Type & entry_helper (std::true_type)
{ return value; }
template <int Index>
auto & entry_helper (std::false_type)
{ return Tuple<Types...>::template entry<Index-1>(); }
template <int Index>
auto & entry()
{ return entry_helper<Index>(std::integral_constant<bool, Index==0>{}); }
在 C++11 中,对于 [=28,您还需要输入尾随 return =]
entry()
和第二个 entry_helper()
正如 Patrick Roberts 所指出的(谢谢!)解决方案,添加尾随 return 类型,适用于带有 g++ 的 C++11 但不适用于 clang++,用于检测 return 的问题在递归上下文中键入。
对于 C++11,我提出了一个完全不同的解决方案,它避免了 entry()
/entry_helper()
递归,但在 class 级别添加了另一个间接级别(添加递归基础 class 结构 Tpl
)。还为 entry()
和 entry_helper()
添加完美转发、无符号索引和常量版本。
#include <utility>
#include <iostream>
#include <type_traits>
template <std::size_t, typename...>
struct Tpl
{ void entry_helper () {} };
template <std::size_t I, typename T, typename ... Ts>
struct Tpl<I, T, Ts...> : public Tpl<I+1u, Ts...>
{
using Tpl<I+1, Ts...>::entry_helper;
Tpl (T && t, Ts && ... ts)
: Tpl<I+1u, Ts...>{std::forward<Ts>(ts)...}, value{std::forward<T>(t)}
{ }
T value;
T & entry_helper (std::integral_constant<std::size_t, I>)
{ return value; }
T const & entry_helper (std::integral_constant<std::size_t, I>) const
{ return value; }
};
template <typename ... Ts>
struct Tuple : public Tpl<0, Ts...>
{
using Tpl<0, Ts...>::entry_helper;
Tuple (Ts && ... ts) : Tpl<0u, Ts...>{std::forward<Ts>(ts)...}
{ }
template <std::size_t I>
auto entry ()
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
template <std::size_t I>
auto entry () const
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) const &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
};
int main()
{
Tuple<int, int, std::string, double> t(1, 2, "Hello World", 3.4);
std::cout << t.entry<1>() << std::endl; // Prints 2
std::cout << t.entry<2>() << std::endl; // Prints "Hello World"
}
假设您至少使用 C++14,您可以使用 auto&
instead of a trailing return type, and as pointed out by template
关键字。
您还可以简化您的定义,因为您只需要一个空基 class,而不是为一种类型实现特化的 class;您的第二个 class 已经为一种类型实现了必要的行为。如果您使用的是 C++17
,则此简化要求您使用std::enable_if
, or if constexpr
重写 entry()
// only needed for C++14 when using std::enable_if
#include <type_traits>
template<typename...>
struct Tuple
{
};
template<typename T, typename... Ts>
struct Tuple<T, Ts...> : public Tuple<Ts...>
{
Tuple(T value, Ts ...args) : value(value), Tuple<Ts...>(args...) { }
T value;
template<std::size_t I, std::enable_if_t<I == 0, bool> = true>
T& entry() { return value; }
template<std::size_t I, std::enable_if_t<I != 0, bool> = true>
auto& entry() { return Tuple<Ts...>::template entry<I - 1>(); }
// // requires C++17 support
// template<std::size_t I>
// auto& entry() {
// if constexpr (I == 0) { return value; }
// else { return Tuple<Ts...>::template entry<I - 1>(); }
// }
};
上试用