【发布时间】:2017-03-03 22:34:55
【问题描述】:
我正在尝试使用 C++11 获取作为模板参数传递的字符串的长度。以下是我目前发现的:
#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;
}
我对结果不是很惊讶,我知道在 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() 创建一个 B 类型,其父类型为 A。 a().b().c() 创建一个类型 C,其父类型为 B,其父类型为 A,等等。
给定一个类型 B 和一个父 A,这是一个独特的类型,它可以有自己的静态缓冲区来保存连接(这就是为什么 l5 不适合我)。然后我可以在静态缓冲区中连续地每一个 strcpy 。我不想使用动态分配的缓冲区,因为此时不必配置我的分配器。
该缓冲区的大小应该足够大以容纳与A 关联的字符串以及与B 关联的字符串是我想要弄清楚的。如果我明确地将 sizeof() 作为一个额外的模板参数(就像上面 sn-p 中的 l4 所做的那样),我可以让它工作,但这会使整个代码阅读起来很繁琐,使用起来也很麻烦。
[编辑 2] 我标记了最有帮助的答案 - 但 Yakk 的答案在 gcc 上也很好,但它没有用 Visual Studio 编译。
我在这一点上的理解是,我们不能依靠 const char [] 与外部链接来提供它们的大小。它可以在本地工作(如果模板与符号在同一单元中编译),但如果const char[] 在要在多个地方使用的头文件中,它将无法工作。
所以我放弃了尝试从 const char* 模板参数中提取长度,并决定使用l4,其中sizeof() 也提供给模板参数。
对于那些好奇整个事情结果如何的人,我在 ideone 上粘贴了一个完整的工作示例:http://ideone.com/A0JwO8
我现在可以在初始化时写入Path<A>::b::c::path() 并在静态缓冲区中获取相应的"b.c" 字符串。
【问题讨论】:
-
你的len5怎么了?这不正是你想要的吗?
-
你可以这样做:
template<typename T, const T& value> struct s; template<typename T, std::size_t N, const T (&value)[N]> struct s<const T[N], value> s {/*..*/};(在c++17中用<auto value>简化)。 -
@SergeyA len5 确实给出了正确的结果,但它不是一种类型。这是对需要实际类型的更复杂问题的简化。
-
你真正想要解决的问题是什么?
-
动态分配缓冲区有什么问题(因此在编译时不关心其大小)?
标签: c++ string c++11 templates string-length