правильная идиома для символьных констант (не std :: string) в c ++ - PullRequest
3 голосов
/ 22 октября 2010

Некоторое время назад я спрашивал о std :: string constants правильный идиом для std :: string constants? .

То, что я забрал из этого, было не для использования констант std :: string, а для использования констант char. Так что лучшая идиома для этого

#define FOO "foo"

const char * const FOO = "foo";

const char FOO[] = "foo";

Желательные функции

  • получить длину во время компиляции. 1 и 3 но не 2 (sizeof не работает на 2)
  • может быть включен в .h без компоновщика жалуюсь. все (я думаю)
  • нет нескольких копий в .o, в связанном выход. зависит от компилятора (Возможно)

Так что кажется, что №3 лучше, но Скотт Мейерс говорит, что нужно использовать # 2 (эффективный пункт C ++ # 1)

краткое изложение ответов

  1. используйте сложный шаблонный код
  2. использовать # 3

Код шаблона кажется излишним. Так что сейчас я иду с # 3;

Но я поразмышляю над кодом шаблона, из-за макро-версии он выглядит хорошо; но мне не нравится тот факт, что он не переносимый (кто знает, может быть, gcc тоже решит, что это неправильно)

Ответы [ 5 ]

4 голосов
/ 22 октября 2010

Для функций, которые вы хотите, ...

  • получить длину во время компиляции,
  • может быть включено в .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, и для этого боль может быть больше, чем усиление.

EDIT
MSVC версии 7.1 до 10.0 неправильно не принимает sizeof. Ниже представлен обходной путь, который прекрасно компилируется с g ++ 4.4.1, Comeau Online 4.3.10.1, MSVC 7.1 и MSVC 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;
}

Приветствия и hth.,

0 голосов
/ 22 октября 2010

Это всего лишь макрос ответа Альфа:

#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 голосов
/ 22 октября 2010

Я думаю, что вы убрали неверную идею из своего предыдущего вопроса.
Строки, как правило, редки и не годятся для поиска, вместо них используйте числа.

Кажется, вы все еще не видите разницу между объявлением в .h и определением хранилища в .cpp, что позволяет избежать нескольких копий.Даже если у вас есть несколько копий (с разными именами констант), у вас все равно будет проблема, о которой вы упоминали в предыдущем вопросе.

имеет один фатальный недостаток.У меня не может быть статического кода уровня модуля, который использует эти строки, так как они, возможно, еще не созданы

Единственный способ избежать этого - привести константы в ту же область, в которой вы сейчас находитесь в static.уровень модуля.

Поместите все связанные вещи в класс!

0 голосов
/ 22 октября 2010

Вот как я это вижу. Я бы не стал использовать ни один из них как есть. Во-первых, я склонен к # 2, но учтите, что вам нужно объявить переменную как extern в .h, и выбрать какой-то .cpp для фактического хранения строки:

// .h
extern const char*const STR;

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

Единственный недостаток - отсутствие длины во время выполнения - не кажется мне реальной причиной для перехода к другому варианту. Если у вас есть несколько строк, вы всегда можете иметь набор целочисленных констант (или #define s) для указания длины каждой строки, например STR_LEN. Если у вас их много, вы все равно не будете писать их под рукой, и тогда вы сможете автоматически генерировать ..._LEN константы одновременно.

0 голосов
/ 22 октября 2010

Ваши желаемые функции противоречивы.

  1. Длина во время компиляции
  2. Определено в заголовочном файле
  3. Одна копия в единицах компиляции

Чтобы получить (1) и (2), вам нужно объявить переменную как static или поместить ее в безымянное пространство имен. Однако это приведет к определению в каждой единице компиляции, которое идет вразрез с (3).

Чтобы получить (2) и (3), вам нужно объявить переменную как extern, но тогда вы не получите (1).

Теперь, если ваш компоновщик умен, он может оптимизировать несколько копий, но я не уверен, позволяет ли это стандарт ...

Я рекомендую синтаксис const char FOO[] = "foo";, объявленный в безымянном пространстве имен или как static, если его нужно найти в определенном пространстве имен. Если строка очень большая, тогда я выберу extern.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...