C++类型特征以在 T1 和 T2 之间进行选择

C++ type traits to select between T1 and T2

本文关键字:之间 T2 行选 选择 T1 类型 特征 C++      更新时间:2023-10-16

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

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模板。

如果您

使用 std::conditional 而不是@Matthieu在他的答案中实现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
};

希望有帮助。

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。