Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在编译时确定参数的唯一性 问题_C++_Templates_C++14_Variadic Templates_Template Meta Programming - Fatal编程技术网

C++ 在编译时确定参数的唯一性 问题

C++ 在编译时确定参数的唯一性 问题,c++,templates,c++14,variadic-templates,template-meta-programming,C++,Templates,C++14,Variadic Templates,Template Meta Programming,我有以下类似数组的容器: template < class _Tp, size_t _Size > class Alphabet { public: template <class... _Ts> constexpr Alphabet(_Ts&& ... ts) : m_data(std::forward<_Ts>(ts)...}) {} private: _Tp m_d

我有以下类似数组的容器:

template <
    class _Tp,
    size_t _Size
> class Alphabet {
public:
    template <class... _Ts>
    constexpr
    Alphabet(_Ts&& ... ts) 
        : m_data(std::forward<_Ts>(ts)...})
    {}
private:
    _Tp m_data[_Size ? _Size : 1];
}

我使用C++14。感谢您的帮助

如果要检查编译时(
static\u assert()
)的
ts..
值,则必须将它们作为编译时已知的值传递

不能在编译时检查
constexpr
构造函数的参数,因为构造函数也可以与运行时值一起使用

我的建议是将
ts..
值作为模板参数传递,因此它们是已知的编译时,因此您可以在
静态断言()测试中检查它们

举例:如果
Tp
是整数类型,则可以将它们作为
std::integer\u序列的参数传递

  template <Tp ... Ts>
  constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
     : m_data{Ts...}
   { static_assert(    sizeof...(Ts) <= Size
                    && are_unique<Ts...>(), "!" ); }
关于
是唯一的()
,您可以使用
未使用的
数组初始化的技巧

  template <Tp T0, Tp ... Ts>
  static constexpr bool is_unique ()
   {
     using unused = bool[];

     bool ret = true;

     (void)unused{ false, ret &= T0 != Ts... };

     return ret;
   }
并按如下方式使用它

constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
constexpr auto{make_Alphabet()};
下面是一个完整的C++14编译示例

#include <utility>
#include <iostream>

template <typename Tp, std::size_t Size>
class Alphabet
 {
   private:
      Tp m_data[Size ? Size : 1U];

      template <Tp T0, Tp ... Ts>
      static constexpr bool is_unique ()
       {
         using unused = bool[];

         bool ret = true;

         (void)unused{ false, ret &= T0 != Ts... };

         return ret;
       }

      // ground case
      template <typename = void>
      static constexpr bool are_unique ()
       { return true; }

      // recursive case
      template <Tp T0, Tp ... Ts>
      static constexpr bool are_unique ()
       { return is_unique<T0, Ts...>() && are_unique<Ts...>(); }

   public:
      template <Tp ... Ts>
      constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
         : m_data{Ts...}
       { static_assert(    sizeof...(Ts) <= Size
                        && are_unique<Ts...>(), "!" ); }
 };

template <typename Tp, Tp ... Ts>
constexpr Alphabet<Tp, sizeof...(Ts)> make_Alphabet ()
 { return { std::integer_sequence<Tp, Ts...>{} }; }

int main()
 {
   // compilation error (static_assert failed "!")
   //constexpr Alphabet<char, 3>
   //   aba{std::integer_sequence<char, 'a', 'b', 'a'>{}};

   // compile
   constexpr Alphabet<char, 3>
      abc{std::integer_sequence<char, 'a', 'b', 'c'>{}};

   // compilation error (static_assert failed "!")
   //constexpr auto abca{ make_Alphabet<char, 'a', 'b', 'c', 'a'>() };

   // compile
   constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
 }
#包括
#包括
模板
类字母表
{
私人:
Tp m_数据[大小?大小:1U];
模板
静态constexpr bool是唯一的()
{
使用unused=bool[];
bool-ret=真;
(void)未使用的{false,ret&=T0!=Ts…};
返回ret;
}
//案情
模板
静态constexpr bool是唯一的()
{返回true;}
//递归案例
模板
静态constexpr bool是唯一的()
{return is_unique()&&are_unique();}
公众:
模板
constepr字母表(std::integer_sequence const&)
:m_数据{Ts..}

{static_assert(sizeof…(Ts)参数参数值永远不是constexpr,您可以使用
std::integral_constant
参数。或者通过
template class Alphabet;
更改您的类。这并不能解决问题,但名称以下划线开头,后跟大写字母(
\u Tp
\u Size
\u Ts
)包含两个连续下划线的名称保留供实现使用。不要在代码中使用它们。常规函数和构造函数参数永远不会是
constexpr
,因为可以使用运行时值调用它们。如果要强制在编译时执行此操作,则需要使用模板;如果要使用不是内置类型或指针的类型,这在C++20之前是不可能的,因为非类型模板参数只允许某些类型。如果您只想允许它在编译时发生(如果值可用),那么可以使用
constepr
函数进行检查,如果出现问题,则引发异常(如果在编译时进行计算,这将成为一个错误)。@DanielH我也这么想。不幸的是,我的印象是我可以将参数设置为
constexpr
。不过,如果编译器允许,我会按照你说的做,并尝试在编译时对字母表进行计算。
error: non-constant condition for static assertion
     static_assert(detail::is_unique(ts...),
                                     ^
error: 'ts#0' is not a constant expression
  template <Tp ... Ts>
  constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
     : m_data{Ts...}
   { static_assert(    sizeof...(Ts) <= Size
                    && are_unique<Ts...>(), "!" ); }
  // ground case
  template <typename = void>
  static constexpr bool are_unique ()
   { return true; }

  // recursive case
  template <Tp T0, Tp ... Ts>
  static constexpr bool are_unique ()
   { return is_unique<T0, Ts...>() && are_unique<Ts...>(); }
  template <Tp T0, Tp ... Ts>
  static constexpr bool is_unique ()
   {
     using unused = bool[];

     bool ret = true;

     (void)unused{ false, ret &= T0 != Ts... };

     return ret;
   }
template <typename Tp, Tp ... Ts>
constexpr Alphabet<Tp, sizeof...(Ts)> make_Alphabet ()
 { return { std::integer_sequence<Tp, Ts...>{} }; }
constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
#include <utility>
#include <iostream>

template <typename Tp, std::size_t Size>
class Alphabet
 {
   private:
      Tp m_data[Size ? Size : 1U];

      template <Tp T0, Tp ... Ts>
      static constexpr bool is_unique ()
       {
         using unused = bool[];

         bool ret = true;

         (void)unused{ false, ret &= T0 != Ts... };

         return ret;
       }

      // ground case
      template <typename = void>
      static constexpr bool are_unique ()
       { return true; }

      // recursive case
      template <Tp T0, Tp ... Ts>
      static constexpr bool are_unique ()
       { return is_unique<T0, Ts...>() && are_unique<Ts...>(); }

   public:
      template <Tp ... Ts>
      constexpr Alphabet (std::integer_sequence<Tp, Ts...> const &)
         : m_data{Ts...}
       { static_assert(    sizeof...(Ts) <= Size
                        && are_unique<Ts...>(), "!" ); }
 };

template <typename Tp, Tp ... Ts>
constexpr Alphabet<Tp, sizeof...(Ts)> make_Alphabet ()
 { return { std::integer_sequence<Tp, Ts...>{} }; }

int main()
 {
   // compilation error (static_assert failed "!")
   //constexpr Alphabet<char, 3>
   //   aba{std::integer_sequence<char, 'a', 'b', 'a'>{}};

   // compile
   constexpr Alphabet<char, 3>
      abc{std::integer_sequence<char, 'a', 'b', 'c'>{}};

   // compilation error (static_assert failed "!")
   //constexpr auto abca{ make_Alphabet<char, 'a', 'b', 'c', 'a'>() };

   // compile
   constexpr auto abcd{ make_Alphabet<char, 'a', 'b', 'c', 'd'>() };
 }