Подтвердить что ты не робот

Шаблон Мета-программирование с помощью Char Массивы как параметры

Я играю с TMP в GCC 4.3.2 половинной реализации С++ 11, и мне было интересно, есть ли способ как-то сделать следующее:

template <char x, char... c>
struct mystruct {
...
};

int main () {

   mystruct<"asdf">::go();

}

Это, очевидно, не позволит мне сделать это именно так, и я подумал, что мне повезет, используя пользовательские литералы, чтобы преобразовать строку asdf во время компиляции, но GCC 4.3 не поддерживает пользователя -пределенные литералы...

Любые предложения? Я бы предпочел не делать "a", "s", "d", "f", поскольку это сильно мешает моим планам для этого проекта.

4b9b3361

Ответ 1

К сожалению, вам все равно придется разбить его на отдельные символы, например:

myTemplate<'s','t','r','i','n','g'>

По моему скромному мнению, это огромный надзор в новом стандарте. Некоторые другие люди согласились и попытались реализовать поведение в GCC с довольно хорошими результатами. Вы можете найти эту тему здесь.

Изменить: некоторые странные проблемы со ссылкой, поэтому вырезать и вставить из этого:

http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/9b0edd169ba2ce3c

Ответ 2

Я решил проблему, подобную этой. Нам понадобился другой тип для каждого имени

template< const char* the_name >
class A
{
    public:
    const char* name( void )
    {
        return the_name;
    }
};

extern const char g_unique_name[]; // defined elsewhere
typedef A<g_unique_name> A_unique;

Это даст вам время доступа к имени и уникальному экземпляру. Однако он не позволит вам получить доступ к отдельным символам во время выполнения.

Если вам нужен индивидуальный доступ к символу, единственный способ его достижения - с помощью заданного пользователем литерала. С++ 0x будет расширен, чтобы позволить синтаксис в вашей основной функции выше, но он все равно привяжет шаблон к указателю на символ, а не к массиву времени компиляции символов.

Ответ 3

A " string" недавно был добавлен в Boost.MPL, позволяющий писать:

typedef mpl::string<'asdf'> asdf;
typedef mpl::push_back<asdf, mpl::char_<'!'> >::type asdf_bang;

BOOST_ASSERT(0 == std::strcmp(mpl::c_str<asdf_bang>::value, "asdf!"));

Обратите внимание, что приведенный выше пример немного надуман, поскольку "строки", состоящие из более чем 4 символов, должны быть разделены. Например:

typedef mpl::string<'hell','o wo','rld'> hello;

Ответ 4

Попробуйте следующее:

extern const char SOMESTRING[] = "stringhere"; //extern linkage required!

template<const char * const STR>
struct MyStruct
{
  static std::string doThis() { return STR; }
};



MyStruct<SOMESTRING>   testObj; //ok!

Крис

Ответ 5

В С++ 11 нет способа хранить временную строку в любом месте во время компиляции. Поэтому я могу предложить вам такой подход: (Это быстро сделанный эскиз, но он хорошо описательный)

#include <stdio.h>

template <char...>
struct StringTuple;

template <char TargHead>
struct StringTuple<TargHead> {
    static constexpr char kSymbol = TargHead;

    static void print() {
        printf(kSymbol ? "%c\n" : "\n", kSymbol);
    }
};

template <char TargHead, char... TargTail>
struct StringTuple<TargHead, TargTail...> {
    using Next = StringTuple<TargTail...>;
    static constexpr char kSymbol = TargHead;

    static void print() {
        if (kSymbol) {
            printf("%c", kSymbol);
            Next::print();
        } else {
            printf("\n");
        }
    }
};

constexpr int length(char *string) {
    return (string[0] == 0) ? 1 : (length(string + 1) + 1);
}

constexpr char get(char *string, int i) {
    return i < length(string) ? string[i] : 0;
}

#define ST(string) \
    StringTuple< \
    get(string, 0), \
    get(string, 1), \
    get(string, 2), \
    get(string, 3), \
    get(string, 4), \
    get(string, 5), \
    get(string, 6), \
    get(string, 7), \
    get(string, 8), \
    get(string, 9), \
    get(string, 10), \
    get(string, 11), \
    get(string, 12), \
    get(string, 13), \
    get(string, 14), \
    get(string, 15), \
    get(string, 16), \
    get(string, 17), \
    get(string, 18), \
    get(string, 19), \
    get(string, 20), \
    get(string, 21), \
    get(string, 22), \
    get(string, 23), \
    get(string, 24), \
    get(string, 25), \
    get(string, 26), \
    get(string, 27), \
    get(string, 28), \
    get(string, 29), \
    get(string, 30), \
    get(string, 31), \
    get(string, 32), \
    get(string, 33), \
    get(string, 34), \
    get(string, 35), \
    get(string, 36), \
    get(string, 37), \
    get(string, 38), \
    get(string, 39), \
    get(string, 40), \
    get(string, 41), \
    get(string, 42) \
    >

int main() {
    ST("Hello, compile-time world!")::print();
}

Bash код для создания части макроса:

for i in `seq 0 42`; do echo "    get(string, $i), \\"; done

Вам необходимо передать большое количество (1000 или более) в этот генератор, чтобы поддерживать все ваши строки, и вам нужно сделать статическое утверждение, если строка превышает этот предел.


Я использую такие сгенерированные макросы в своих собственных научных проектах. Я знаю, что это кажется грязным, но это работает. Пример использования сгенерированного макроса:

#define PRINT(a) print(a);
FOREACH_MACRO(PRINT, a, b, c) // print(a);print(b);print(c);

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

Ответ 6

Я не уверен, чего вы хотите достичь, но когда вы передаете "asdf" в шаблон, он имеет тип char *, а значение - это адрес строки. Таким образом, простой подход, подобный описанному, потерпит неудачу. Трудно рекомендовать что-либо, не зная, какую проблему вы пытаетесь решить в первую очередь.

Ответ 7

Вы не можете этого сделать. Из 14.3.2 в стандарте:

Аргумент шаблона для непигового шаблона-шаблона без шаблона должен быть одним из следующих:

  • интегральное постоянное выражение интегрального или перечисляемого типа; или
  • имя несимметричного шаблона; или
  • адрес объекта или функции с внешней связью, включая шаблоны функций и шаблоны-шаблоны функций   но исключая нестатические члены класса, выраженные как и id-expression, где и является необязательным, если имя относится к
  • функция или массив, или если соответствующий шаблон-параметр является ссылкой; или
  • константное выражение, которое вычисляет значение нулевого указателя (4.10); или
  • константное выражение, которое вычисляет значение указателя нулевого элемента (4.11); или
  • указатель на элемент, выраженный как описано в 5.3.1.
  • [Примечание: строковый литерал (2.13.4) не удовлетворяет требованиям любой из этих категорий и, следовательно, не является допустимым аргументом шаблона

Ответ 8

Цитата из новой стандартной черновики:

14.3.2 Шаблон аргументов non-type [temp.arg.nontype]

2 Примечание: строковый литерал (2.13.4) не удовлетворяет требованиям любая из этих категорий и, следовательно, не приемлемый шаблонный аргумент.

Пример:

template<class T, char* p>
class X 
{ 
X(); 
X(const char* q) { /... / } 
}; 

X<int, "Studebaker"> x1; // error: string literal as template-argument char p[] = "Vivisectionist";
X<int,p> x2; // OK

Попробуйте, но я не уверен, потому что http://gcc.gnu.org/gcc-4.3/cxx0x_status.html не говорит об этой функции.

Ответ 9

Мотти ошибается.

К сожалению, текущий стандарт (С++ 11) не поддерживает Variadic template literal operator для строковых параметров, это возможно только для чисел.

template <char... Args>
operator ""_op();

...

1212_op; // legal, calls operator ""_op<'1','2','1','2'>;
"1212"_op; // illegal

Я не понял цели этого ограничения.