C++类型特性,用于在T1和T2之间进行选择

que*_*en3 11 c++ templates metaprogramming type-traits template-meta-programming

我希望模板根据某些条件从两种类型中进行选择.例如

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;
};
Run Code Online (Sandbox Code Playgroud)

当然,将条件传递给select_base(使其通用)会很有用,但硬编码的解决方案也更容易和更好.

这是我尝试过的示例解决方案,但总是选择T1:http://ideone.com/EnVT8

问题是如何实现select_base模板.

Naw*_*waz 18

如果您在答案中使用@Matthieu实现std::conditionalif_类模板而不是类模板,那么您的解决方案将减少到:

template <typename T, typename U>
struct select_base
{
   typedef typename std::conditional<std::is_base_of<T, Base>::value, T, U>::type base_type;
};
Run Code Online (Sandbox Code Playgroud)

或者只是这个:

template <typename T, typename U>
struct select_base : std::conditional<std::is_base_of<T, Base>::value, T, U> {};
Run Code Online (Sandbox Code Playgroud)

看起来更好.

这两个解决方案之间的区别在于,在第一个解决方案中,您给出了嵌套类型的程序员友好名称,正如我已经给出的那样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;
Run Code Online (Sandbox Code Playgroud)

那么你可以使用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
};
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.


Mat*_* M. 8

C++ 14(及以后):

template <typename T, typename U>
struct select_base:
    std::conditional_t<std::is_base_of<T, Base>::value, T, U> {};
Run Code Online (Sandbox Code Playgroud)

同样,您可以改为使用:

template<typename T, typename U>
using select_base = std::conditional_t<std::is_base_of_v<T,Base>, T, U>;
Run Code Online (Sandbox Code Playgroud)

使用它们时,可以观察到这两种方法之间的差异.例如,在第一种情况下,如果你必须使用::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 {};
//                 ^                                       ^~~~~~
Run Code Online (Sandbox Code Playgroud)

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; };
Run Code Online (Sandbox Code Playgroud)

is_base_of 稍微复杂一点,Boost中提供了一个我不会在这里重现的实现.

然后,参见C++ 11.