Передача строкового литерала в качестве параметра в шаблонный класс C ++ - PullRequest
37 голосов
/ 09 января 2010

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

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

Спасибо

Ответы [ 12 ]

37 голосов
/ 09 января 2010

Далее от ответа Нейла: один из способов использовать строки с шаблонами так, как вы хотите, - это определить класс признаков и определить строку как признак типа.

#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
22 голосов
/ 09 января 2010

К сожалению, C ++ в настоящее время не поддерживает использование строковых литералов (или реальных литералов) в качестве параметров шаблона.

Но перечитайте ваш вопрос, это то, что вы спрашиваете? Вы не можете сказать:

foo <"bar"> x;

но вы можете сказать

template <typename T>
struct foo {
   foo( T t ) {}
};

foo <const char *> f( "bar" );
12 голосов
/ 05 декабря 2017

Вы можете иметь 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 / а / 64cd254136dd0272

11 голосов
/ 09 августа 2013

Это решение с MPLLIBS для передачи строк в качестве аргументов шаблона (C ++ 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

lib на github: https://github.com/sabel83/mpllibs

11 голосов
/ 31 марта 2011
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();
}

Попробуйте добавить адрес функции в качестве аргумента шаблона.

6 голосов
/ 13 января 2010

Исходя из ваших комментариев под ответом Ниль, другая возможность заключается в следующем:

#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
4 голосов
/ 27 июля 2017

Нельзя передать строковый литерал напрямую в качестве параметра шаблона.

Но вы можете подобраться ближе:

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'>.

    Это то, что вышеуказанное решение делает для вас за кадром.

4 голосов
/ 09 января 2010

РЕДАКТИРОВАТЬ: хорошо название вашего вопроса вводит в заблуждение

"Мне нужен класс, который принимает два параметра в своем конструкторе. Первый может быть либо int, double, либо float, поэтому второй всегда является строковым литералом" my string ", поэтому я предполагаю, что 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?");
}

Если вы удалите комментарий в последней строке, вы получите ошибку компилятора.


Строковые литералы не разрешены в C ++ 2003

ИСО / МЭК 14882-2003 §14.1:

14.1 Параметры шаблона

Нетипизированный шаблон-параметр должен иметь один из следующих (необязательно квалифицированных cv) типов:

- целочисленный или перечислимый тип,

- указатель на объект или указатель на функцию,

- ссылка на объект или ссылка на функцию,

- указатель на член.

ИСО / МЭК 14882-2003 §14.3.2:

14.3.2 Шаблонные нетиповые аргументы

Шаблонный аргумент для нетипичного, не шаблонного шаблонного параметра должен быть одним из:

- целочисленная константа-выражение целочисленного или перечислительного типа; или

- имя нетипового шаблона-параметра; или

- адрес объекта или функции с внешней связью, включая шаблоны функций и идентификаторы шаблонов функций, но исключая нестатические члены класса, выраженный как & 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 

- конец примера] - конец заметки]

И похоже, что он не изменится в следующем C ++ 0X, см. Текущий черновик 14.4.2 Аргументы нетипичных шаблонов .

3 голосов
/ 09 января 2010

Я хочу класс, который принимает два параметра в своем конструкторе.Первый может быть либо int, double, либо float, а второй всегда является строковым литералом «my string»

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
   {
   }
};

Я не уверен, но вы этого хотите?

2 голосов
/ 09 января 2010

строковый литерал "my string", поэтому я предполагаю, что 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...