Передача строкового литерала в качестве параметра в класс шаблонов С++
Мне нужен класс, который принимает два параметра в своем конструкторе. Первый может быть либо int, double, либо float, поэтому <typename T>
, а второй всегда является строковым литералом "моя строка", поэтому я думаю, const char * const
.
Может ли кто-нибудь дать мне компилируемый код, который объявляет простой шаблон класса, как описано, и объявляет объект этого класса?
Спасибо
Ответы
Ответ 1
Извините, С++ в настоящее время не поддерживает использование строковых литералов (или реальных литералов) в качестве параметров шаблона.
Но перечитывая свой вопрос, это то, что вы спрашиваете? Вы не можете сказать:
foo <"bar"> x;
но вы можете сказать
template <typename T>
struct foo {
foo( T t ) {}
};
foo <const char *> f( "bar" );
Ответ 2
Далее от Нила ответ: один способ использования строк с шаблонами, как вы хотите, - определить класс признаков и определить строку как признак типа.
#include <iostream>
template <class T>
struct MyTypeTraits
{
static const char* name;
};
template <class T>
const char* MyTypeTraits<T>::name = "Hello";
template <>
struct MyTypeTraits<int>
{
static const char* name;
};
const char* MyTypeTraits<int>::name = "Hello int";
template <class T>
class MyTemplateClass
{
public:
void print() {
std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl;
}
};
int main()
{
MyTemplateClass<int>().print();
MyTemplateClass<char>().print();
}
печатает
My name is: Hello int
My name is: Hello
Ответ 3
inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; }
template <const wchar_t *GetLiteralFunc(void)>
class MyType
{
void test()
{
std::cout << GetLiteralFunc;
}
}
int main()
{
MyType<GetTheStringYouWant>.test();
}
Попробуйте это, указав адрес функции как аргумент шаблона.
Ответ 4
Это решение с MPLLIBS для передачи строк в качестве аргументов шаблона (С++ 11).
#include <iostream>
#include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs
#include <boost/mpl/string.hpp>
// -std=c++11
template<class a_mpl_string>
struct A
{
static const char* string;
};
template<class a_mpl_string>
const char* A< a_mpl_string >
::string { boost::mpl::c_str< a_mpl_string >::value }; // boost compatible
typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type;
int main ( int argc, char **argv )
{
std::cout << a_string_type{}.string << std::endl;
return 0;
}
печатает:
any string as template argument
Библиотека на github: https://github.com/sabel83/mpllibs
Ответ 5
Вы можете иметь параметр шаблона const char*
не типового типа и передать ему переменную const char[]
со static
связью, которая не так уж далека от прямой передачи строкового литерала.
#include <iostream>
template<const char *str>
struct cts {
void p() {std::cout << str;}
};
static const char teststr[] = "Hello world!";
int main() {
cts<teststr> o;
o.p();
}
http://coliru.stacked-crooked.com/a/64cd254136dd0272
Ответ 6
Основываясь на ваших комментариях по ответу Niel, есть еще одна возможность:
#include <iostream>
static const char* eventNames[] = { "event_A", "event_B" };
enum EventId {
event_A = 0,
event_B
};
template <int EventId>
class Event
{
public:
Event() {
name_ = eventNames[EventId];
}
void print() {
std::cout << name_ << std::endl;
}
private:
const char* name_;
};
int main()
{
Event<event_A>().print();
Event<event_B>().print();
}
печатает
event_A
event_B
Ответ 7
Вы не можете передавать строковый литерал непосредственно в качестве параметра шаблона.
Но вы можете приблизиться:
template<class MyString = typestring_is("Hello!")>
void MyPrint() {
puts( MyString::data() );
}
...
// or:
MyPrint<typestring_is("another text")>();
...
Все, что вам нужно, это небольшой заголовочный файл из здесь.
Альтернативы:
-
Определите глобальный char const *
и передайте его в шаблон как указатель. (здесь)
Недостаток: требуется дополнительный код вне списка аргументов шаблона. Это не подходит, если вам нужно указать строковый литерал "inline".
-
Используйте нестандартное языковое расширение. (здесь)
Недостаток: не гарантируется работа со всеми компиляторами.
-
Используйте BOOST_METAPARSE_STRING
. (здесь)
Недостаток: ваш код будет зависеть от библиотеки Boost.
-
Используйте пакет параметров вариационного шаблона char, например. str_t<'T','e','s','t'>
.
Это то, что приведенное выше решение делает для вас за кулисами.
Ответ 8
Мне нужен класс, который принимает два параметра в своем конструкторе. Первый может быть либо int, double, либо float, поэтому, а второй всегда является строковым литералом "моя строка"
template<typename T>
class demo
{
T data;
std::string s;
public:
demo(T d,std::string x="my string"):data(d),s(x) //Your constructor
{
}
};
Я не уверен, но это то, что вы хотите?
Ответ 9
ИЗМЕНИТЬ: ОК название вашего вопроса, похоже, вводит в заблуждение
"Я хочу класс, который принимает два параметра в своем конструкторе. Первый может быть либо int, double, либо float, поэтому, а второй всегда является строковым литералом" моя строка ", поэтому я предполагаю const char * const."
Похоже, вы пытаетесь достичь:
template<typename T>
class Foo
{
public:
Foo(T t, const char* s) : first(t), second(s)
{
// do something
}
private:
T first;
const char* second;
};
Это будет работать для любого типа для первого параметра: int
, float
, double
, что угодно.
Теперь, если вы действительно хотите ограничить тип первого параметра только int
, float
или double
; вы можете придумать что-то более сложное, например
template<typename T>
struct RestrictType;
template<>
struct RestrictType<int>
{
typedef int Type;
};
template<>
struct RestrictType<float>
{
typedef float Type;
};
template<>
struct RestrictType<double>
{
typedef double Type;
};
template<typename T>
class Foo
{
typedef typename RestrictType<T>::Type FirstType;
public:
Foo(FirstType t, const char* s) : first(t), second(s)
{
// do something
}
private:
FirstType first;
const char* second;
};
int main()
{
Foo<int> f1(0, "can");
Foo<float> f2(1, "i");
Foo<double> f3(1, "have");
//Foo<char> f4(0, "a pony?");
}
Если вы удалите комментарий в последней строке, вы получите ошибку компилятора.
Строковые литералы не разрешены С++ 2003
ISO/IEC 14882-2003 §14.1:
14.1 Параметры шаблона
Параметр шаблона, не относящийся к типу, должен иметь один из следующих типов (необязательно):
- интегральный или перечисляемый тип,
- указатель на объект или указатель на функцию,
- ссылка на объект или ссылку на функцию,
- указатель на элемент.
ISO/IEC 14882-2003 §14.3.2:
14.3.2 Шаблон аргументов non-type
Аргумент шаблона для непигового шаблона-шаблона без шаблона должен быть одним из следующих:
- интегральное постоянное выражение интегрального или перечисляемого типа; или
- имя несимметричного шаблона; или
- адрес объекта или функции с внешней связью, включая шаблоны функций и шаблоны-шаблоны функций, но исключая нестатические члены класса, выраженные как и выражение id, где и является необязательным, если имя относится к функции или массиву, или если соответствующий шаблон-параметр является ссылкой; или
- указатель на элемент, выраженный как описано в 5.3.1.
[Примечание: строковый литерал (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
-end example] -end note]
И похоже, что это не изменится в предстоящем С++ 0X, см. текущий проект 14.4.2. Шаблоны непиговых аргументов.
Ответ 10
строковый литерал "моя строка", поэтому я думаю, const char * const
Собственно, строковые литералы с n видимыми символами имеют тип const char[n+1]
.
#include <iostream>
#include <typeinfo>
template<class T>
void test(const T& t)
{
std::cout << typeid(t).name() << std::endl;
}
int main()
{
test("hello world"); // prints A12_c on my compiler
}
Ответ 11
Я боролся с подобной проблемой и, наконец, придумал краткую реализацию, которая распаковывает строковый литерал в пакет параметров шаблона char... без использования расширения шаблона оператора литерала gnu.
#include <utility>
template <char ... Chars>
struct type_string_t {
static constexpr const char data[sizeof... (Chars)] = {Chars...};
};
template <char s(std::size_t), std::size_t... I>
auto type_string_impl(std::index_sequence<I...>) {return type_string_t<s(I)...>();};
#define type_string(s) decltype (type_string_impl<[](std::size_t i) {return s[i];}> \
(std::make_index_sequence<sizeof (s)>()))
static_assert (std::is_same<type_string("String_A"),
type_string("String_A")>::value);
static_assert (!std::is_same<type_string("String_A"),
type_string("String_B")>::value);
Ответ 12
Может быть, не то, что запрашивает OP, но если вы используете boost
, вы можете создать макрос, например, так:
#define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value
Затем используйте следующее:
template<const char* str>
structe testit{
};
testit<C_STR("hello")> ti;