【问题标题】:How can I make sure a type only appear once in a template parameter? [duplicate]如何确保一个类型在模板参数中只出现一次? [复制]
【发布时间】:2021-11-12 02:03:23
【问题描述】:

假设我有一个别名:

using bar = foo<string, string, int>;

如何确保“字符串”在参数中只出现一次?如果出现多次,则抛出错误。

我做了一个函数来计算一个类型出现在参数中的次数,但没有实现这个想法。

template <class T> 
constexpr std::size_t type_count_impl(std::size_t count = 0) {
    return count;
};

template <class T, class T1, class... Types>
constexpr std::size_t type_count_impl(std::size_t count = 0) {
    return type_count_impl<T, Types...>(count + (std::is_same<T, T1>::value ? 1 : 0));
};

template <class T, class... Types> 
constexpr std::size_t type_count() {
    return type_count_impl<T, Types...>();
};

【问题讨论】:

标签: c++ templates


【解决方案1】:

对于一个简单的编译时错误,如果可变参数包中的 any 类型重复,这很简单:

template <typename T> struct Base{};
template <typename... Ts> struct NoDuplicates : Base<Ts>... { 
    constexpr operator bool() const { return true; }
};

就是这样,如果您需要它,它的编译速度将比任何递归模板元编程、折叠表达式或类型特征方法更快。事实上,我知道在编译时没有更快的技术。 这是因为一个类不允许从同一个基类继承两次。它继承自 Base&lt;T&gt; 而不仅仅是 T 的原因是,如果 T 是您无法继承的类型,例如原始整数值、数组或 void 等。

使用方法:

template <typename... Ts>
class Foo {
    static_assert(NoDuplicates<Ts...>{}); 
};

Foo<int, char, int> foo; // ERROR (see below)
<source>:3:34: error: duplicate base type 'Base<int>' invalid
    3 | template <typename... Ts> struct NoDuplicates : Base<Ts>... {

现在,如果您想要编译错误,但想要计算一个布尔值来指示是否有任何重复,这会稍微复杂一些,但也不算太糟糕。评论显示要检查的 3 个案例:

template <typename T, typename... Rest>
constexpr bool hasDuplicates() {
    // Check T against each item in Rest, and if any match we have duplicates
    if ((std::is_same_v<T, Rest> || ...)) 
        return true;
    
    // Is there anything left to check in Rest?  If not, no duplicates.
    if constexpr (sizeof...(Rest) == 0)
        return false;

    // T isn't duplicated, but is anything in Rest duplicated?
    return hasDuplicates<Rest...>();
}

同样可以使用:

template <typename... Ts>
class Foo {
    static_assert(not hasDuplicates<Ts...>()); 
};

Foo<int, std::string, std::string> foo; // Error, there are dupes

最后,如果您只关心特定类型是否重复,那就更容易了:

// Check if Needle is found 2 or more times in this Haystack
template <typename Needle, typename... Haystack>
constexpr bool hasDuplicateInList() {
    return ((std::is_same_v<Needle, Haystack> + ...)) > 1;
}

就“抛出”而言,如果这是您想要的,如果您检测到布尔值在普通 if 中具有不允许的值,您总是可以抛出异常

【讨论】:

    【解决方案2】:

    您的type_count_impl() 不需要接受参数,只需在Types... 的大小为0 时返回0。所以你的type_count() 可以简化为:

    #include <type_traits>
    
    template <class T> 
    constexpr std::size_t type_count() {
      return 0;
    };
    
    template <class T, class T1, class... Types>
    constexpr std::size_t type_count() {
      return type_count<T, Types...>() + std::is_same<T, T1>::value;
    };
    
    #include <string>
    
    static_assert(type_count<std::string, std::string, std::string, int>() == 2);
    static_assert(type_count<int, std::string, std::string, int>() == 1);
    static_assert(type_count<int>() == 0);
    

    Demo.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      相关资源
      最近更新 更多