Шаблон Мета-программирование с помощью 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", поскольку это сильно мешает моим планам для этого проекта.
Ответы
Ответ 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
Я не понял цели этого ограничения.
Ответ 10
См. обсуждение здесь, по-видимому, возможно: http://cpp-next.com/archive/2012/10/using-strings-in-c-template-metaprograms/