Как сделать «static_assert» конструкцию шаблона в списке инициализатора члена? - PullRequest
2 голосов
/ 05 мая 2019

У меня есть MyClass, который является шаблоном класса.Я хотел предоставить конструктор списка инициализации r, чтобы мне было удобно писать:

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

С другой стороны, Я не хочу иметь дубликаты в этом списке, так как этот класс имел в видуиметь только уникальные пользовательские входы.Я видел много способов проверить дубликаты в массиве, и я придумал следующую функцию has_duplicates().

Я попытался объединить идею проверки, являются ли std::initializer_list<T> 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<T> constutorаргументы, в приведенном выше случае?

1 Ответ

3 голосов
/ 05 мая 2019

То, что вы пытаетесь сделать, статическое утверждение для проверки аргументов конструктора, (насколько я знаю) просто невозможно.

A 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
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...