【问题标题】:How to `static_assert` the construction of a template class in member initializer list?如何`static_assert`在成员初始化列表中构造模板类?
【发布时间】:2019-05-05 20:16:27
【问题描述】:

我有MyClass,这是一个模板类。我想提供一个初始化 r 列表构造函数,以便我可以方便地编写:

MyClass<int> Arr0{ 1,  2,  3, 4, 5, 8 };

另一方面,我不想在这个列表中有重复项,因为这个类意味着只有唯一的用户输入。我见过很多方法来检查数组中的重复项,我想出了has_duplicates() 以下函数。

我尝试结合检查std::initializer_list&lt;T&gt;ed 临时元素(或数组)是否包含成员初始化列表本身中的任何重复元素如果它包含static_assert(),则模板实例化,因此不会构造此类的任何对象。

以下是我的代码的最小示例。

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
#include <initializer_list>

template <typename Iterator> // function to check duplicates(which works fine)
constexpr bool has_duplicates(Iterator start, Iterator end)
{
    if (start == end) return false;
    using Type = typename std::remove_reference_t<decltype(*end)>;
    std::map<Type, std::size_t> countMap;
    for (; start != end; ++start)
    {
        countMap[*start]++;
        if (countMap[*start] >= 2) return true;
    }
    return false;
}

template <typename T> class MyClass
{
private:
    std::vector<T> m_vec;

public:
    MyClass(std::initializer_list<T> a)
        : (has_duplicates(a.begin(), a.end()) //-----> here is the problem
            ? static_assert(false, " the array has duplicates....")
            : m_vec(a)
           )
    {
        std::cout << "Constriction successful....";
    }
};

int main()
{
    std::vector<int> test{ 1, 2, 3, 4, 1 };
    std::cout << std::boolalpha 
        << has_duplicates(test.begin(), test.end()) << std::endl; // works
    MyClass<int> Arr0{ 1,  2,  3, 4 }; // error
    return 0;
}

在 MSVC 16.0(C++17 标志)中编译时,这给了我错误:

error C2059: syntax error: 'static_assert'
note: while compiling class template member function 'MyClass<int>::MyClass(std::initializer_list<_Ty>)'
      with
      [
          _Ty=int
      ]
note: see reference to function template instantiation 'MyClass<int>::MyClass(std::initializer_list<_Ty>)' being compiled
      with
      [
          _Ty=int
      ]
note: see reference to class template instantiation 'MyClass<int>' being compiled
error C2143: syntax error: missing ';' before '}'
error C2059: syntax error: ')'
error C2447: '{': missing function header (old-style formal list?)

它说一个简单的语法错误,但我没有看到任何 static_assert.

谁能帮我找出错误?

在上述情况下,防止构造 std::initializer_list&lt;T&gt; constutor 参数的正确方法是什么?

【问题讨论】:

  • 我认为这是不可能的,因为 std::initializer_list&lt;T&gt; 的值只能在运行时确定。
  • std::map 不是 constexpr 类;所以你的has_duplicates() 不能初始化constexpr
  • @cpplearner:给定多个翻译单元,甚至不可能静态地知道每个可能的initializer_list 参数的长度
  • @cpplearner:我的意思是你甚至不知道可能提供的 set 长度。

标签: c++ c++17 template-meta-programming static-assert stdinitializerlist


【解决方案1】:

你想要做的,一个 static 断言来检查构造函数的参数,(据我所知)根本不可能。

static_assert() 工作在编译时,MyClass 对象在运行时被初始化(可以被初始化)。

我能想象到的最好的方法是 make_MyClass() 函数,它接收参数列表作为模板参数

template <auto v0, auto ... vs>
auto make_MyClass ()
 {
   static_assert( false == has_duplicates<v0, vs...>() );

   return MyClass<decltype(v0)>{ v0, vs... };
 }

所以你可以执行static_assert(),因为现在你知道编译时间的值;我重写了has_duplicates() 函数如下,因为你的原始函数不能有效地constexpr(因为std::map 不是)

template <typename = void>
constexpr bool has_duplicates ()
 { return false; }

template <auto v0, auto ... vs>
constexpr bool has_duplicates ()
 { return ((v0 == vs) || ... ) || has_duplicates<vs...>(); }

以下是完整的编译示例

#include <iostream>
#include <vector>
#include <initializer_list>

template <typename = void>
constexpr bool has_duplicates ()
 { return false; }


template <auto v0, auto ... vs>
constexpr bool has_duplicates ()
 { return ((v0 == vs) || ... ) || has_duplicates<vs...>(); }  

template <typename T> class MyClass
{
private:
    std::vector<T> m_vec;

public:
    MyClass(std::initializer_list<T> a) : m_vec{a}
     { std::cout << "Constriction successful...."; }
};

template <auto v0, auto ... vs>
auto make_MyClass ()
 {
   static_assert( false == has_duplicates<v0, vs...>() );

   return MyClass<decltype(v0)>{ v0, vs... };
 }

int main ()
 {
    std::cout << std::boolalpha 
        << has_duplicates<1, 2, 3, 4, 1>() << std::endl;

    auto mc0 = make_MyClass<1, 2, 3, 4, 5>(); // compile
    //auto mc1 = make_MyClass<1, 2, 3, 4, 1>(); // static_assert error
 }

【讨论】:

  • 该死的@max...你很擅长templates。我总是看到您的代码太好了,以至于我无法很好地遵循;)。但是这个((v0 == vs) || ... || has_duplicates&lt;vs...&gt;());我有。不幸的是,MSVC 给了我错误godbolt.org/z/g5OE_s,而 GCC 接受了这个错误:wandbox.org/permlink/R18zgEqtzmM7w02N。谢谢你的解释。
  • @Const - 我想 MSVC 是错误的(但我不确定)。无论如何,我已经修改了has_duplicates() 递归版本以使其满意(但使用“/std:c++17”来启用 C++17,而不是“-std-c++17”)
猜你喜欢
  • 1970-01-01
  • 2011-05-11
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-11
  • 1970-01-01
  • 2016-05-03
相关资源
最近更新 更多