确保可变参数模板不包含重复项
Ensuring that a variadic template contains no duplicates
我想我的整个问题在标题中都有很好的描述。我正在尝试创建可变 class 模板(在 C++11、C++14 或 C++1z 中)。
template<typename ...Types> struct MyVariadicTemplate {};
并确保 MyVariadicTemplate
的任何实例化中的类型列表是单射的,因此,例如,如果我调用以下代码:
MyVariadicTemplate<int, double, int> x;
它不会编译(我很乐意使用 static_assert
以某种方式做到这一点)。
我将不胜感激。
这可以借助两个元函数来编写。
首先,IsContained
检查类型是否出现在类型列表中。
template <typename T, typename... List>
struct IsContained;
template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
enum { value = std::is_same<T, Head>::value || IsContained<T, Tail...>::value };
};
template <typename T>
struct IsContained<T>
{
enum { value = false };
};
其次,IsUnique
检查类型列表是否不包含重复项。它使用 IsContained
检查所有元素组合。
template <typename... List>
struct IsUnique;
template <typename Head, typename... Tail>
struct IsUnique<Head, Tail...>
{
enum { value = !IsContained<Head, Tail...>::value && IsUnique<Tail...>::value };
};
template <>
struct IsUnique<>
{
enum { value = true };
};
有了这些工具,静态断言就非常简单了:
template <typename... Ts>
struct NoDuplicates
{
static_assert(IsUnique<Ts...>::value, "No duplicate types allowed");
};
如果您可以访问 C++1z 折叠表达式,则可以通过对 IsContained
执行以下操作来简化@TheOperator 的回答:
template <typename T, typename... List>
struct IsContained;
template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
enum { value = std::is_same<T, Head>::value || (IsContained<T, Tail>::value && ... && true) };
};
template <typename T>
struct IsContained<T>
{
enum { value = false };
};
不同之处在于折叠表达式有更大的机会重新使用 class 实例化。如果你使用了很多参数或者有很多重复比较,这个可能有更快的编译时间。一如既往,自己测试一下。
使用 c++17 这很容易。
#include <type_traits>
template <typename T, typename... Ts>
struct are_distinct: std::conjunction<
std::negation<std::is_same<T, Ts>>...,
are_distinct<Ts...>
>{};
template <typename T>
struct are_distinct<T>: std::true_type{};
算法与 and 的算法相同,但表达更简洁。
然后,针对您的具体问题,您可以这样使用它:
template<typename ...Types>
struct MyVariadicTemplate {
static_assert(are_distinct<Types...>::value, "Types must be distinct");
/* rest of the code */
};
但是,鉴于这是 O(n²),我想知道是否有办法降低算法的复杂性? Boost::mpl's unique<> is O(n),但我无法理解它使用的算法。
我想我的整个问题在标题中都有很好的描述。我正在尝试创建可变 class 模板(在 C++11、C++14 或 C++1z 中)。
template<typename ...Types> struct MyVariadicTemplate {};
并确保 MyVariadicTemplate
的任何实例化中的类型列表是单射的,因此,例如,如果我调用以下代码:
MyVariadicTemplate<int, double, int> x;
它不会编译(我很乐意使用 static_assert
以某种方式做到这一点)。
我将不胜感激。
这可以借助两个元函数来编写。
首先,IsContained
检查类型是否出现在类型列表中。
template <typename T, typename... List>
struct IsContained;
template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
enum { value = std::is_same<T, Head>::value || IsContained<T, Tail...>::value };
};
template <typename T>
struct IsContained<T>
{
enum { value = false };
};
其次,IsUnique
检查类型列表是否不包含重复项。它使用 IsContained
检查所有元素组合。
template <typename... List>
struct IsUnique;
template <typename Head, typename... Tail>
struct IsUnique<Head, Tail...>
{
enum { value = !IsContained<Head, Tail...>::value && IsUnique<Tail...>::value };
};
template <>
struct IsUnique<>
{
enum { value = true };
};
有了这些工具,静态断言就非常简单了:
template <typename... Ts>
struct NoDuplicates
{
static_assert(IsUnique<Ts...>::value, "No duplicate types allowed");
};
如果您可以访问 C++1z 折叠表达式,则可以通过对 IsContained
执行以下操作来简化@TheOperator 的回答:
template <typename T, typename... List>
struct IsContained;
template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
enum { value = std::is_same<T, Head>::value || (IsContained<T, Tail>::value && ... && true) };
};
template <typename T>
struct IsContained<T>
{
enum { value = false };
};
不同之处在于折叠表达式有更大的机会重新使用 class 实例化。如果你使用了很多参数或者有很多重复比较,这个可能有更快的编译时间。一如既往,自己测试一下。
使用 c++17 这很容易。
#include <type_traits>
template <typename T, typename... Ts>
struct are_distinct: std::conjunction<
std::negation<std::is_same<T, Ts>>...,
are_distinct<Ts...>
>{};
template <typename T>
struct are_distinct<T>: std::true_type{};
算法与
然后,针对您的具体问题,您可以这样使用它:
template<typename ...Types>
struct MyVariadicTemplate {
static_assert(are_distinct<Types...>::value, "Types must be distinct");
/* rest of the code */
};
但是,鉴于这是 O(n²),我想知道是否有办法降低算法的复杂性? Boost::mpl's unique<> is O(n),但我无法理解它使用的算法。