模板参数的字符串的constexpr长度 [英] constexpr length of a string from template parameter

查看:65
本文介绍了模板参数的字符串的constexpr长度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图获取使用C ++ 11作为模板参数传递的字符串的长度.到目前为止,这是我发现的东西:

  #include< iostream>#include< cstring>extern const char HELLO [] =世界你好!";template< const char _S []>constexpr size_t len1(){return sizeof(_S);}template< const char _S []>constexpr size_t len2(){return std :: strlen(_S);}模板< const char _S [],std :: size_t _Sz = sizeof(_S)>constexpr size_t len3(){return _Sz-1;}template< unsigned int _N>constexpr size_t len5(const char(& str)[_ N]){返回_N-1;}int main(){枚举{l1 = len1< HELLO>(),//l2 = len2< HELLO>()无法编译l3 = len3< HELLO>(),l4 = len3< HELLO,sizeof(HELLO)>(),l5 = len5(HELLO),};std :: cout<<l1<<std :: endl;//输出4//std :: cout<<l2<<std :: endl;std :: cout<<l3<<std :: endl;//输出3std :: cout<<l4<<std :: endl;//输出14std :: cout<<l5<<std :: endl;//输出14返回0;} 

我对结果并不感到惊讶,我知道在len1()和len2()的情况下,数组的大小会丢失,尽管信息是在编译时出现的.

是否也可以将有关字符串大小的信息传递给模板?像这样:

  template< const char _S [unsigned int _N]>constexpr size_t len6(){return _N-1;} 


[根据上下文和意图进行编辑]我放弃了在编译时连接一组字符串的尝试,因此我尝试在初始化时进行操作.编写类似 a().b().c().str()之类的内容时,会输出"abc" ,而 a().b().str()将输出"ab"

使用模板, a().b()创建父类型为 A B 类型. a().b().c()创建类型为 C 的父类型为 B 的父类型为 A等.

给定类型为 B 并为其父类 A ,这是唯一类型,它可以拥有自己的静态缓冲区来保存串联(这就是l5 对我不利).然后,我可以在一个静态缓冲区中连续对每个字符串进行strcpy`操作.我不想使用动态分配的缓冲区,因为此时不一定需要配置我的分配器.

该缓冲区的大小应该足够大以容纳与 A 关联的字符串和与 B 关联的字符串.如果我将sizeof()作为一个额外的模板参数(如上面的代码片段中的 l4 一样)进行显式设置,则可以使它正常工作,但是这会使整个代码难以阅读且使用起来很麻烦./p>


我标记了最有用的答案-但是Yakk的答案在gcc上也不错,但它不能与Visual Studio一起编译.

我现在的理解是,我们不能依靠带有外部链接的 const char [] 来提供它们的大小.它可能在本地工作(如果模板以与符号相同的单元编译),但是如果 const char [] 在头文件中以便在多个地方使用,则它将无法工作.

因此,我放弃了尝试从const char *模板参数中提取长度的决定,并决定使用 l4 ,其中还将 sizeof()提供给模板参数.

对于那些好奇整个结果如何的人,我在ideone上粘贴了完整的工作示例: http://ideone.com/A0JwO8

我现在可以在初始化时在静态缓冲区中写入 Path< A> ::: b :: c :: path()并获取相应的"bc" 字符串

解决方案

要在编译时连接字符串,
使用gnu扩展名,您可以这样做:

  template< typename C,C ... cs>结构字符{使用str_type = C [1 + sizeof ...(cs)];静态constexpr C str [1 + sizeof ...(cs)] = {cs ...,0};constexpr运算符const str_type&()const {return str;}};template< typename C,C ... cs>constexpr C Chars< C,cs ...> :: str [1 + sizeof ...(cs)];//需要GNU扩展模板< typename C,C ... cs>constexpr Chars C,cs ...>运算符" _cs(){return {};}模板< typename C,C ... lhs,C ... rhs>constexpr Chars C,lhs ...,rhs ...>运算符+(Chars C,lhs ...> ;, Chars C,rhs ...>){return {};} 

随用法

  constexpr auto hi ="Hello" _cs +"world \ n" _cs;std :: cout<<你好; 

演示

没有gnu扩展名,您必须使用一些MACRO将文字转换为char序列,就像我一样./p>

I am trying to obtain the length of a string passed as a template argument using C++11. Here is what I have found so far:

#include <iostream>
#include <cstring>
extern const char HELLO[] = "Hello World!!!";

template<const char _S[]>
constexpr size_t len1() { return sizeof(_S); }

template<const char _S[]>
constexpr size_t len2() { return std::strlen(_S); }

template<const char _S[], std::size_t _Sz=sizeof(_S)>
constexpr size_t len3() { return _Sz-1; }

template<unsigned int _N>
constexpr size_t len5(const char(&str)[_N])
{
    return _N-1;
}

int main() {
    enum {
        l1 = len1<HELLO>(),
        // l2 = len2<HELLO>() does not compile
        l3 = len3<HELLO>(),
        l4 = len3<HELLO, sizeof(HELLO)>(),
        l5 = len5(HELLO),
    };
    std::cout << l1 << std::endl;  // outputs 4
    // std::cout << l2 << std::endl;
    std::cout << l3 << std::endl; // outputs 3
    std::cout << l4 << std::endl; // outputs 14
    std::cout << l5 << std::endl; // outputs 14
    return 0;
}

I am not very surprised with the results, I understand that the size of the array is lost in the case of len1() and len2(), although the information is present at compile time.

Is there a way to pass the information about the size of the string to the template as well? Something like:

template<const char _S[unsigned int _N]>
constexpr size_t len6() { return _N-1; }


[Edit with context and intent] I gave up trying to concatenate a set of strings at compile time so I am trying to do it at initialization time. Writing something like a().b().c().str() would output "abc" while a().b().str() would output "ab"

Using templates, a().b() creates a type of B with a parent type A. a().b().c() creates a type C with a parent type B which has a parent type A, etc.

Given a type B with a parent A, this is a unique type and it can have it's own static buffer to hold the concatenation (this is why l5 isn't good for me). I could then strcpy` each one consecutively in a static buffer. I don't want to use a dynamically allocated buffer because my allocator is not necessarily configured at this point.

The size of that buffer which should be big enough to hold the string associated with A and the string associated with B is what I am trying to figure out. I can get it to work if I explicitly sizeof() as an extra template parameter (as done with l4 in the snippet above), but that make the whole code heavy to read and cumbersome to use.


[Edit 2] I marked the answer that was most helpful - but Yakk's answer was also good on gcc but except it did not compile with Visual Studio.

My understanding at this point is that we cannot rely on const char [] with external linkage to provide their size. It may work locally (if the template is compiled in the same unit as the symbol), but it won't work if the const char[] is in a header file to be used in multiple places.

So I gave up on trying to extract the length from the const char* template paramter and decided to live with l4 where the sizeof() is also provided to the template arguments.

For those who are curious how the whole thing turned out, I pasted a full working sample on ideone: http://ideone.com/A0JwO8

I can now write Path<A>::b::c::path() and get the corresponding "b.c" string in a static buffer at initialization.

解决方案

To concatenate string at compile time,
with gnu extension, you may do:

template<typename C, C...cs> struct Chars
{
    using str_type = C[1 + sizeof...(cs)];
    static constexpr C str[1 + sizeof...(cs)] = {cs..., 0};

    constexpr operator const str_type&() const { return str; }
};

template<typename C, C...cs> constexpr C Chars<C, cs...>::str[1 + sizeof...(cs)];

// Requires GNU-extension
template <typename C, C...cs>
constexpr Chars<C, cs...> operator""_cs() { return {}; }

template <typename C, C...lhs, C...rhs>
constexpr Chars<C, lhs..., rhs...>
operator+(Chars<C, lhs...>, Chars<C, rhs...>) { return {}; }

With usage

constexpr auto hi = "Hello"_cs + " world\n"_cs;

std::cout << hi;

Demo

Without gnu extension, you have to use some MACRO to transform literal into char sequence, as I do there.

这篇关于模板参数的字符串的constexpr长度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆