将字符串文字作为参数传递给C ++模板类

时间:2010-01-09 10:57:34

标签: c++ templates

我想要一个在其构造函数中包含两个参数的类。第一个可以是int,double或float,所以<typename T>,第二个总是字符串文字“my string”,所以我想const char * const

任何人都可以给我一些可编译的代码,它声明了一个简单的类模板,并声明了该类的对象吗?

由于

15 个答案:

答案 0 :(得分:37)

进一步来自Neil的回答:根据需要使用带模板的字符串的一种方法是定义一个traits类,并将字符串定义为该类型的特征。

#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

答案 1 :(得分:22)

抱歉,C ++目前不支持使用字符串文字(或真正的文字)作为模板参数。

但重新阅读你的问题,那就是你在问什么?你不能说:

foo <"bar"> x;

但你可以说

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

foo <const char *> f( "bar" );

答案 2 :(得分:11)

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();
}

尝试将函数的地址作为模板参数传递。

答案 3 :(得分:11)

这是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

github上的lib:https://github.com/sabel83/mpllibs

答案 4 :(得分:11)

可以拥有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

答案 5 :(得分: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

答案 6 :(得分:4)

编辑:好的,你的问题的标题似乎有误导性

  

“我想要一个在其构造函数中包含两个参数的类。第一个可以是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;

};

这适用于任何类型,第一个参数:intfloatdouble,等等。

现在,如果您确实要将第一个参数的类型限制为仅intfloatdouble;你可以想出更精彩的东西,比如

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不允许使用字符串文字

ISO / IEC14882-2003§14.1:

  

14.1模板参数

     

非类型模板参数应具有以下(可选的)限定类型之一:

     

- 整数或枚举类型,

     

- 指向对象或指向函数的指针,

     

- 对象的引用或对函数的引用,

     

- 指向成员的指针。

ISO / IEC14882-2003§14.3.2:

  

14.3.2模板非类型参数

     

非类型非模板模板参数的模板参数应为以下之一:

     

- 整数或枚举类型的整数常量表达式;或

     

- 非类型模板参数的名称;或

     

- 具有外部链接的对象或函数的地址,包括函数模板和函数template-id,但不包括非静态类成员,表示为&amp; id表达式中的&amp;如果名称引用函数或数组,或者相应的template-parameter是引用,则是可选的;或

     

- 指向成员的指针,如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]

在即将到来的C ++ 0X see the current draft 14.4.2 Template non-type arguments中看起来似乎不会改变。

答案 7 :(得分:4)

您不能直接将字符串文字作为模板参数传递。

但你可以近距离接触:

template<class MyString = typestring_is("Hello!")>
void MyPrint() {
  puts( MyString::data() );
}

...
// or:
MyPrint<typestring_is("another text")>();
...

您只需要here的小标题文件。

<强>备选方案:

  • 定义全局char const *并将其作为指针传递给模板。 (here

    缺点:需要模板参数列表之外的其他代码。如果你需要指定字符串文字&#34; inline&#34;它是不合适的。

  • 使用非标准语言扩展程序。 (here

    缺点:不保证可以与所有编译器一起使用。

  • 使用BOOST_METAPARSE_STRING。 (here

    缺点:您的代码将取决于Boost库。

  • 使用char的可变参数模板参数包,例如str_t<'T','e','s','t'>

    这就是上述解决方案在幕后为您所做的事情。

答案 8 :(得分:3)

  

我想要一个在其构造函数中包含两个参数的类。第一个可以是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
   {
   }
};

我不确定,但这是你想要的东西吗?

答案 9 :(得分:2)

  

字符串文字“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
}

答案 10 :(得分:2)

使用代理static constexpr const char type_name_str[] = {"type name"};将字符串作为模板参数传递。使用[]定义字符串很重要。

#include <iostream>

template<typename T, const char* const t_name>
struct TypeName
{
public:

    static constexpr const char* Name()         
    {                                   
        return t_name;
    };                                  

};

static constexpr const char type_name_str[] = {"type name"};

int main() 
{
    std::cout<<TypeName<float, type_name_str>::Name();
    return 0;
}

答案 11 :(得分:2)

template <char... elements>
struct KSym /* : optional_common_base */ {
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  const char z[sizeof...(elements) + 1] = { elements..., '\0' };
  // We can have properties, we don't need anything to be constexpr for Rs
};
template <typename T, T... chars>
auto&& operator""_ksym() { 
  static KSym<chars...> kSym; // Construct the unique singleton (lazily on demand)
  return kSym;
}
static auto ksym_example1 = "a unique string symbol1\n"_ksym.z;
static auto ksym_example2 = "a unique string symbol2\n"_ksym.z;
auto dont_care = []() {
  ::OutputDebugString(ksym_example1);
  ::OutputDebugString("a unique string symbol2\n"_ksym.z);
  assert("a unique string symbol1\n"_ksym.z == ksym_example1);
  assert("a unique string symbol2\n"_ksym.z == ksym_example2);
  return true; 
}();

在Windows上使用Clang 11的生产环境中,以上内容对我有用。

(已编辑)我现在在 Windows 上的 clang 中完全使用 this

// P0424R1: http://www.open-std.org/jtc1/SC22/wg21/docs/papers/2017/p0424r1.pdf
template <char... chars_ta> struct KSymT;
template <typename T, T... chars_ta> // std::move(KSymT<chars_ta...>::s);
auto operator""_ksym()->KSymT<chars_ta...>& { return KSymT<chars_ta...>::s; }
struct KSym {
  virtual void onRegister() {}
  virtual std::string_view zview_get() = 0;
};

template <char... chars_ta>
struct KSymT : KSym {
  inline static KSymT s;
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  inline static constexpr char z[sizeof...(chars_ta) + 1] = { chars_ta..., '\0' };
  inline static constexpr UIntPk n = sizeof...(chars_ta);
  // We can have properties, we don't need anything to be constexpr for Rs
  virtual std::string_view zview_get() { return std::string_view(z); };
  //#KSym-support compare with `Af_CmdArgs`
  inline bool operator==(const Af_CmdArgs& cmd) {
    return (cmd.argl[0] == n && memcmp(cmd.argv[0], z, n) == 0);
  }
};

答案 12 :(得分:1)

我一直在努力解决类似的问题,最后想出了一个简洁的实现,该实现将字符串文字解压缩为char ...模板参数包,而没有使用gnu文字运算符模板扩展

display:flex;
justify-content:center;
align-items:center;

答案 13 :(得分:1)

C ++ 20 fixed_string +“非类型模板参数中的类类型”

显然,对此的建议已被接受,但随后被删除:"String literals as non-type template parameters"

删除该内容的部分原因是,它被认为很容易与另一个被接受的建议"Class Types in Non-Type Template Parameters"一起使用。

已接受的投标包含具有以下语法的示例:

template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;

我将尝试使用一个示例进行更新,一旦看到支持它的编译器,该示例就会告诉我所有内容。

A Redditor还显示了以下内容,如果您定义了自己的basic_fixed_string版本(尚未包含在标准库中),则可以在GCC master上进行以下编译:https://godbolt.org/z/L0J2K2

template<unsigned N>
struct FixedString {
    char buf[N + 1]{};
    constexpr FixedString(char const* s) {
        for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
    }
    constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;

template<FixedString T>
class Foo {
    static constexpr char const* Name = T;
public:
    void hello() const;
};

int main() {
    Foo<"Hello!"> foo;
    foo.hello();
}

g++ -std=c++2a 9.2.1 from the Ubuntu PPA无法使用以下命令进行编译:

/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status

参考书目:https://botondballo.wordpress.com/2018/03/28/trip-report-c-standards-meeting-in-jacksonville-march-2018/

  

最后,EWG决定取消先前批准的提案,以允许在非类型模板参数中使用字符串文字,这是因为允许非类型模板参数中的类类型(刚刚被批准)的更通用的功能就足够了替代。 (这是上次会议的一次更改,当时我们似乎都希望两者兼而有之。)主要区别在于,您现在必须将字符数组包装到一个结构中(请考虑fixed_string或类似的结构),并将其用作模板参数类型。 (P0424的用户定义文字部分仍在继续,并对允许的模板参数类型进行了相应的调整。)

对于C ++ 17 if constexprif / else at compile time in C++?

来说,这尤其酷

这种功能似乎与C ++ 20中令人敬畏的“ constexpr everything”提案相一致,例如:Is it possible to use std::string in a constexpr?

答案 14 :(得分:0)

也许不是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;