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

Передача строкового литерала в качестве параметра в класс шаблонов С++

Мне нужен класс, который принимает два параметра в своем конструкторе. Первый может быть либо int, double, либо float, поэтому <typename T>, а второй всегда является строковым литералом "моя строка", поэтому я думаю, const char * const.

Может ли кто-нибудь дать мне компилируемый код, который объявляет простой шаблон класса, как описано, и объявляет объект этого класса?

Спасибо

4b9b3361

Ответ 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;