2010-10-21 17 views
3

前一阵子我询问std :: string常量correct idiom for std::string constants?C++中的字符串(不是std :: string)常量的正确习惯用法

我从那里拿走的是而不是使用std :: string常量,而是使用char字符串常量。那么对于

#define FOO "foo" 

const char * const FOO = "foo"; 

const char FOO[] = "foo"; 

可取的特点

  • 获取长度在编译时最好的成语。 1 & 3但是 不是2(sizeof不能在2上工作)
  • 可以被包括在.h中而没有连接器 抱怨。所有(我认为)
  • 没有在.o中的多个副本,在链接的 输出中。依赖于编译器 (可能)

所以它看起来像#3是最好的,但斯科特迈尔斯说,使用#2回答

  1. 使用(有效的C++项目#1)

    汇总快乐复杂的模板代码

  2. 使用#3

模板代码感觉就像矫枉过正。所以现在我去#3;

但是我会反思模板代码,宏观版本会使它看起来好看;但我不喜欢它不便携的事实(谁知道,也许海湾合作委员会会认为它也是错误的)

回答

0

您所需的功能是矛盾的。

  1. 在编译时长
  2. 单拷贝整个编译单元定义在头文件

为了得到(1)和(2),你需要变量声明为static或把它放在一个未命名的名字空间中。但是,这会导致每个编译单元中的定义不符合(3)。 (2)和(3),你需要声明变量为extern,但是你不会得到(1)。

现在,如果你的连接是聪明的,它可能会优化掉的多个副本,但我不知道,如果标准允许它...

我推荐一位不愿透露姓名的命名空间或声明的语法const char FOO[] = "foo";如果需要在特定名称空间中找到它,则返回static。如果字符串非常大,那么我去extern

+0

恩,功能不矛盾。呃,现在解释一下,我将不得不添加一个答案。就这样吧。干杯, – 2010-10-21 21:54:45

+0

#define可以在sizeof – pm100 2010-10-21 22:41:09

+0

@ pm100下正常工作:它的行为与静态类似,因为它给你(1)和(2)的代价是在每个编译单元中生成一个副本(尽管它保证不会是除非实际使用,否则生成)。 – 2010-10-21 23:01:18

0

这就是我所看到的。我不会使用任何这些。首先,我倾向于#2,但考虑到你必须在.h中声明该变量为extern,并选择一些。CPP实际存储的字符串:

// .h 
extern const char*const STR; 

// .cpp 
const char*const STR = "abc"; 

唯一的缺点,不必在运行时间的长短,似乎并没有给我一个真正的原因移动到其他选项。如果您有多个字符串,则始终可以有一组整数常量(或#define s)来指定每个字符串的长度,例如STR_LEN。如果你有很多这样的参数,那么不会把它们写在手边,然后你可以同时自动生成常量。

+0

如果在编译时不需要长度,那么没有理由不使用'std :: string'。 – 2010-10-21 22:16:55

+0

@André:可能是'std :: sting'使用的动态内存开销。但是,是的,一般来说没有太多关于不使用'std :: string'的意思。 – 2010-10-21 22:33:32

+0

实际上不是 - const * char const可以安全地放置在多个头文件 – pm100 2010-10-21 22:40:34

4

对于您想要的功能,...

  • 在编译时获取长度,
  • 可以包含在.H没有连接怨天尤人,
  • 中的.o无多拷贝,在联动输出,

...你可以使用模板不变成语,像

template< class Dummy > 
struct Foo_ 
{ 
    static char const s[]; 
}; 

template< class Dummy > 
char const Foo_<Dummy>::s[] = "Blah blah"; 

typedef Foo_<void> Foo; // Now you can refer to Foo:s 


#include <iostream> 
using namespace std; 
int main() 
{ 
    cout << sizeof(Foo::s) << " bytes: \"" << Foo::s << "\"\n"; 
} 

您可以将生成包装在宏中。

然而,据我所知,唯一的实用工具是支持char/wchar_t-agnostic代码,并且为此痛苦可能会大于增益。

编辑
MSVC版本7.1向上穿过10.0正确不接受sizeof。以下是一个解决方法,可以很好地编译g ++ 4.4.1,Comeau Online 4.3.10.1,MSVC 7.1和M​​SVC 10.0。

#include <stddef.h> 

typedef ptrdiff_t Size; 

// Substitute a more general countOf 
template< Size n > 
struct SizedBuf { char sizer[n]; }; 

template< class Type, Size n > 
SizedBuf<n> countOf_(Type (&)[n]) { return n; } 

#define COUNT_OF(array) sizeof(countOf_(array).sizer) 

#define DEF_STRING(name, value)        \ 
    template<class>           \ 
    struct name##_constant_          \ 
    {               \ 
     static char const str[];        \ 
     static Size const length = COUNT_OF(value) - 1; \ 
    };               \ 
                   \ 
    template< class Type >          \ 
    char const name##_constant_<Type>::str[] = value;   \ 
                   \ 
    template< class Type >          \ 
    Size const name##_constant_<Type>::length;    \ 
                   \ 
    typedef name##_constant_<void> name; 


DEF_STRING(a, "Argh, MSVC!") 
DEF_STRING(b, "Blah blah") 
DEF_STRING(c, "Currently there's no 'inline' for data in C++.") 


#include <iostream> 

template< char const* s > 
void foo() { std::cout << "foo() says: " << s << std::endl; } 

int main() 
{ 
    using namespace std; 

    int const x[a::length] = {}; // Showing off compile time constant. 
    foo<a::str>();     // Showing off external linkage. 

    cout << a::length << " characters: \"" << a::str << "\"." << endl; 
} 

干杯&心连心,

+0

+1中。好主意。 Crazy,but nice :) – 2010-10-21 22:06:46

+1

小心解释一下'const char FOO [] =“foo”;'syntax?我很难通过*一个奇怪的模板和一个宏,以及失去从'char'到'wchar_t'的轻松更改支持,并且仍然在每个编译单元中生成一个副本... – 2010-10-21 22:13:23

+0

@André:你的建议不符合OP的第三项要求。关于“轻松改变”的评论也没有意义,对不起。 Cheers&hth。, – 2010-10-21 22:17:38

0

我认为你从你前面的问题采取了错误的想法了。
字符串倾向于稀疏并且不适合查找,请改用数字。

在.h中声明和在.cpp中定义存储以避免多个副本之间似乎仍然没有区别。即使您有多个副本(使用不同的常量名称),您仍然会遇到您在上一个问题中提到的问题。

有一个致命的缺陷。我不能,因为他们可能没有已建成尚未

避免这种情况是把常量与你目前拥有的静态模块级相同的范围内的唯一方法是使用这些字符串静态模块级代码。

把所有相关的东西放在一个类!

+0

第2 - 我明确地理解了这些差异。我们谈论的是文字无害重复的情况,在其他情况下,我们谈论的是链接器barfs,我知道链接器barfs的具体含义,不知道什么是链接器barf。在我期望的功能列表中,我有很高的需求 - 没有链接器barfs,一个很好的拥有;没有膨胀 – pm100 2010-10-21 22:45:43

+0

第二关于类的问题与它无关如果我有全局静态,那么加载顺序没有定义我可以重新排列我的代码,使我没有全局静态,但那不是点我注意到,如果你有全局静态,建议不起作用 – pm100 2010-10-21 22:47:16

0

这仅仅是阿尔夫的回答macro'd:

#include <iostream> 

#define string_constant(pName, pLiteral)     \ 
     template <typename = void>       \ 
     struct pName##_detail        \ 
     {             \ 
      static const char value[];      \ 
     };             \ 
                  \ 
     template <typename T>        \ 
     const char pName##_detail<T>::value[] = pLiteral; \ 
                  \ 
     typedef pName##_detail<> pName 

string_constant(my_constant, "this is a literal"); 

int main() 
{ 
    std::cout << my_constant::value << std::endl; 
    std::cout << sizeof my_constant::value << std::endl; 
} 

codepad。似乎没有在VS2010中工作。 :/

+0

重新“似乎在VS2010中没有工作”,我没有检查,但上面的一个区别代码和我的是上面使用默认的模板参数。干杯&hth。, – 2010-10-21 22:32:46

+0

@Alf:这不应该有所作为(这对我来说是更清洁)。但无论如何我都改变了它,只是为了确定,同样的错误。看起来还有另外一个违规案例。 (FFS) – GManNickG 2010-10-21 22:38:32

+0

g ++和Comeau在线接受代码,MSVC 10(我也检查过7.1)没有。检查匹配它的模板参数似乎MSVC在'main'中错误地将数组的类型视为不完整。在C++ 0x草案N3092§3.9/ 6中讨论了翻译单元内数组类型的完成(当大小变得已知时从不完整到完整)。对不起,我不知道MSVC的解决方法。我尝试了几件事,但都没有成功。 :-( – 2010-10-21 23:19:18

相关问题