Constexpr转换为const char []

它发生在很多人身上,而且发生在我身上。 我被卡在C ++编译时字符串中。

我决定采取显然无法使用的方法:使用template <char...>类。

这是我想出来的,这是非常普遍的,没有什么特别的,也是行不通的。

template <char... chars> class string
{
public:

    static constexpr const char value[] = {chars...};

    constexpr string()
    {
    }

    constexpr operator decltype(value) & () const
    {
        return value;
    }
};

template <char... chars> constexpr const char string <chars...> :: value[];

我的想法是创建一个string实例constexpr constructible并公开某种constexpr投射,以便提供其内容。

现在,如果我这样做

static constexpr const char x[] = "ciao";

template <const char * str> void print()
{
    std :: cout << str << std :: endl;
}

print <x> ();

这是有效的,并说ciao 。 如果我这样做,我也会得到ciao

std :: cout << string <'c', 'i', 'a', 'o'> {} << std :: endl;

要么

print <string <'c', 'i', 'a', 'o', ''> :: value> ();

但是当我这样做

print <string <'c', 'i', 'a', 'o', ''> {}> ();

我得到: No matching function for call to print

我绝对错过了一些东西。 做我想做的事情是不可行的? 让一个实例做一个constexpr转换来以某种方式返回value ? 如果这样做的话,我可以在编译时轻松地进行操作和字符串操作,“唯一”的缺点是超无聊的'i', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n'

进一步实验

我做了另一个完美的实验。

template <char... chars> class string
{
public:
   constexpr string()
   {
   }

   constexpr operator size_t () const
   {
      return sizeof...(chars);
   }
};

template <size_t length> void print()
{
   std :: cout << length << std :: endl;
}

print <string <'c', 'i', 'a', 'o'> {}> ();

它打印出一个漂亮的4


在C ++ 14中,模板参数对模板非类型参数的限制是:

非类型,非模板模板参数的模板参数应该是以下之一:
*对于整型或枚举类型的非类型模板参数,模板参数类型的转换常量表达式(5.19); 要么
*非类型模板参数的名称; 要么
*一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的完整对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板id,但不包括非静态类成员(忽略括号)作为& ID表达,其中的ID-expression是对象或函数的名称,除了&如果名称是指功能或阵列,并且如果相应的模板的参数将被省略,可以省略是一个参考; 要么
*一个常量表达式,其值为一个空指针值(4.10); 要么
*一个常量表达式,其值为空成员指针值(4.11); 要么
*一个指向成员的指针,如5.3.1所述; 要么
* std::nullptr_t类型的常量表达式。

在你的例子中, string<'c', 'i', 'a', 'o', ''>{}都不是这些。 请注意,第一个项目符号仅限于整数或枚举类型,而const char*不是那些(整型类型的例外是允许您的“Further experiments”示例编译的项目)。 其他项目符号均不适用。 所以符合C ++ 14应该拒绝你的代码。

解决方法是直接传递底层字符数组:

print<string<'c', 'i', 'a', 'o', ''>::value>();

或者将类型本身作为模板类型参数,并在函数中使用print ::value

template <class T>
void print() {
    std::cout << T::value << std::endl;
}

print<string<'c', 'i', 'a', 'o', ''>>();

要么...


你会很高兴知道在C ++ 17中,事情会变得更好。 参见N4198,其中有激励性的例子:

template<int *p> struct A {};
int n;
A<&n> a; // ok

constexpr int *p() { return &n; }
A<p()> b; // error

该文件对模板非类型参数提出了更少的限制,这将使上述示例格式良好。 新的措辞写道:

非类型模板参数的模板参数应该是模板参数类型的转换后的常量表达式(5.20)。 对于引用类型或指针类型的非类型模板参数,常量表达式的值不应引用(或者对于指针类型,不应为地址):
*子对象(1.8),
*一个临时对象(12.2),
*一个字符串文字(2.14.5),
* typeid表达式(5.2.8)的结果,或者*预定义的__func__变量(8.4.1)。

而已。 其他一切都是允许的。

由于string<'c', 'i', 'a', 'o', ''>{}转换为不属于这些东西的指针,所以该示例变得格式良好。 铿锵3.8将编译您的示例在c + + 1z模式(正确),但不是在c + + 14模式(正确)。 GCC还没有实现。 给他们时间。


用户定义的转换不适用于模板参数匹配。

但是,而不是

print <string <'c', 'i', 'a', 'o', ''>{} > ();

...你可以写

print <string <'c', 'i', 'a', 'o', ''>::value> ();

或者你可以定义

template <const char* str>
void print()
{
    std::cout << str << std::endl;
}

template< class Type >
void print()
{
    print<Type::value>();
}

...然后写出来

print <x> ();
print <string <'c', 'i', 'a', 'o', ''>> ();

...其中x是您的命名空间范围

static constexpr const char x[] = "ciao";

注意 :此代码与MinGW g ++ 5.1.0一起编译为-std=c++14 ,但不与Visual C ++ 2015更新2一起编译。这些差异对于推动语言边界的代码很常见。 这个标准正在不断变化,编译器也在不断发展以试图跟上标准,所以这样的代码实际上不是很便携。

链接地址: http://www.djcxy.com/p/34951.html

上一篇: Constexpr cast to const char[]

下一篇: Extract US phone numbers from a string