我希望模板根据某些条件从两种类型中进行选择。 E.g。
struct Base {};
template <typename T1, typename T2>
struct test
{
// e.g. here it should select T1/T2 that is_base_of<Base>
typename select_base<T1, T2>::type m_ValueOfBaseType;
};
当然,将条件传递给select_base(使其通用)会很有用,但硬编码的解决方案也更容易和更好。
以下是我尝试的示例解决方案,但始终选择T1:http://ideone.com/EnVT8
问题是如何实现select_base模板。
答案 0 :(得分:18)
如果您使用@Matthieu在其答案中实施的std::conditional
而不是if_
类模板,那么您的解决方案将减少到此:
template <typename T, typename U>
struct select_base
{
typedef typename std::conditional<std::is_base_of<T, Base>::value, T, U>::type base_type;
};
或者只是这个:
template <typename T, typename U>
struct select_base : std::conditional<std::is_base_of<T, Base>::value, T, U> {};
看起来更好。
这两个解决方案之间的区别在于,在第一个解决方案中,您为嵌套类型提供了一个程序员友好的名称,因为我已经给它base_type
,而在第二个解决方案中解决方案嵌套类型只是type
,看起来不像程序员。
请注意,在上述两种解决方案中,您都必须将嵌套类型用作select_base<T,U>::base_type
(在第一个解决方案中)或select_base<T,U>::type
(在第二个解决方案中 - 并且因此,如果您使用typename
,那么您已经在问题本身中写下了自己。
但是,如果你而不是使用模板别名,定义为:
template<typename T, typename U>
using base_type = typename std::conditional<std::is_base_of<T, Base>::value, T, U>::type;
然后您可以使用base_type<T,U>
而不使用任何嵌套类型和typename
作为:
template <typename T1, typename T2>
struct test
{
//typename select_base<T1, T2>::type m_ValueOfBaseType; //ugly!
base_type<T1, T2> m_ValueOfBaseType; //better
};
希望有所帮助。
答案 1 :(得分:6)
C ++ 14 (及以后):
template <typename T, typename U>
struct select_base:
std::conditional_t<std::is_base_of<T, Base>::value, T, U> {};
同样,你可以改用:
template<typename T, typename U>
using select_base = std::conditional_t<std::is_base_of_v<T,Base>, T, U>;
使用它们时,可以观察到这两种方法之间的差异。例如,在第一种情况下,如果你必须使用::type
,而在第二种情况下,你不要。如果任何依赖类型涉及第一种方法的使用,您还必须使用typename
来协助编译器。第二种方法没有所有这些噪音,因此优于其他方法。
另外,请注意您也可以在C ++ 11中编写类似的类型别名。
<强> C ++ 11 强>:
template <typename T, typename U>
struct select_base:
std::conditional<std::is_base_of<T, Base>::value, T, U>::type {};
// ^ ^~~~~~
<强> C ++ 98 强>:
有条件很容易:
template <typename bool, typename T, typename U>
struct conditional { typedef T type; };
template <typename T, typename U>
struct conditional<false, T, U> { typedef U type; };
is_base_of
稍微复杂一点,Boost中提供了一个我不会在这里重现的实现。
之后,请参阅C ++ 11。