当前位置: 首页 > 知识库问答 >
问题:

如何“static\u assert”在成员初始值设定项列表中构造模板类?

汪驰
2023-03-14

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

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

另一方面,我不想在这个列表中有重复项,因为这个类意味着只有唯一的用户输入。我已经看到了许多检查数组中重复项的方法,并提出了以下函数。

我试图结合检查的想法,是否std::initializer_list

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

#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\u断言,我没有看到任何语法错误。

有人能帮我找出错误吗?

防止构造std::initializer\u列表的正确方法是什么


共有1个答案

姬昀
2023-03-14

就我所知,您试图做的是用静态断言来检查构造函数的参数,这是完全不可能的。

static_assert()在运行时初始化(可以初始化)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()函数,如下所示,因为您的原始函数无法有效地constexr(因为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
 }
 类似资料:
  • 我相信现代C初始值设定项列表对于初始化对象非常有用,甚至不需要定义自己的构造函数: 但是,当我的类从另一个类继承时,这不起作用: 我尝试添加

  • 我有以下代码: 我希望输出是:“base constructor,test:50”,但事实并非如此,因为构造函数是在初始化之前调用的,没有错误或警告,它只是编译。 有什么方法可以让构造函数在之后被调用吗?或者这是总体上的糟糕设计? 我正在尝试将所有的init方法和它们的调用放入构造函数insted中,这个行为阻止了我这样做。

  • 本质上,我想要一个具有数组的模板类,其大小是一个模板参数,以保存常量内容。 类似于: 我一直在搜索和修补一点,几乎有一个解决方法实现了一个中间静态方法,并使用std::array: ...这已经是相当多的样板,但仍然d::array似乎不是从初始化列表中构建的?:-(

  • 在下面的示例中,我需要初始化A::A(H H)构造函数初始值设定项列表中的std::array(因为类H没有默认的构造函数),但我不能使用初始值设定项列表,因为数组大小是一个模板参数。 有办法解决这个问题吗?

  • 我有一个这样的类,除了有多个成员: 我基本上希望对其进行聚合初始化,如下所示: 但由于自定义构造函数的原因,这似乎是不可能的,因此我想使用构造函数参数来模拟它: 这看起来有很多冗余,只是为了在可能的情况下移动和复制,尤其是在成员数量激增的情况下。我想我想要完美的转发? 但是现在我不能像这样使用空的初始化列表调用它: 因为无法推导出初始化列表参数类型。有没有不需要我写的解决方案 ?

  • 我有一个函数模板,它接受任意嵌套的列表并返回一个数组: 当我对一些嵌套的std::initializer\u list使用此函数时,如下所示: 我收到无法推断类型N的错误 无法推断模板参数“N” 如何改进函数模板以推断列表嵌套的次数