我想要一个在其构造函数中包含两个参数的类.第一个可以是int,double或float,所以<typename T>
,第二个总是字符串文字"my string",所以我想const char * const
.
任何人都可以给我一些可编译的代码,声明一个简单的类模板,并声明该类的对象?
谢谢
ami*_*mit 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();
}
Run Code Online (Sandbox Code Playgroud)
版画
My name is: Hello int
My name is: Hello
Run Code Online (Sandbox Code Playgroud)
Moo*_*uck 22
您可以使用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();
}
Run Code Online (Sandbox Code Playgroud)
http://coliru.stacked-crooked.com/a/64cd254136dd0272
小智 21
抱歉,C++目前不支持使用字符串文字(或真正的文字)作为模板参数.
但重新阅读你的问题,那就是你在问什么?你不能说:
foo <"bar"> x;
Run Code Online (Sandbox Code Playgroud)
但你可以说
template <typename T>
struct foo {
foo( T t ) {}
};
foo <const char *> f( "bar" );
Run Code Online (Sandbox Code Playgroud)
Cir*_*四事件 19
C++20 fixed_string
+“非类型模板参数中的类类型”
显然,对此的提议首先被接受,但随后被删除:“字符串文字作为非类型模板参数”
删除的部分原因是它被认为很容易处理另一个被接受的提案:“非类型模板参数中的类类型”。
接受的提案包含一个具有以下语法的示例:
template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;
Run Code Online (Sandbox Code Playgroud)
一旦我看到支持它的编译器,我将尝试用一个示例来更新它,该示例实际上告诉我任何事情。
Redditor还表明以下内容可以在 GCC master 上编译,前提是您定义自己的版本,basic_fixed_string
该版本尚未在标准库中: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();
}
Run Code Online (Sandbox Code Playgroud)
g++ -std=c++2a
来自 Ubuntu PPA 的9.2.1无法编译:
/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
参考书目:https : //botondballo.wordpress.com/2018/03/28/trip-report-c-standards-meeting-in-jacksonville-march-2018/
最后,EWG 决定撤消先前批准的提案,以允许在非类型模板参数中使用字符串文字,因为允许在非类型模板参数中使用类类型的更通用的工具(刚刚批准)是一个足够好的替代品。(这与上次会议相比有所改变,当时看起来我们都想要。)主要区别在于您现在必须将字符数组包装到一个结构中(想想 fixed_string 或类似的),并将其用作模板参数类型。(P0424 的用户自定义字面量部分仍在继续,对允许的模板参数类型进行了相应的调整。)
这在 C++17 中会特别酷if constexpr
:在 C++ 中编译时使用 if/else?
这种特性似乎符合 C++20 中令人敬畏的“constexpr 一切”提案,例如:是否可以在 constexpr 中使用 std::string?
Alw*_*ing 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();
}
Run Code Online (Sandbox Code Playgroud)
尝试使用函数的地址作为模板参数.
Mon*_*omy 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;
}
Run Code Online (Sandbox Code Playgroud)
打印:
any string as template argument
Run Code Online (Sandbox Code Playgroud)
github上的lib:https://github.com/sabel83/mpllibs
根据您在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();
}
Run Code Online (Sandbox Code Playgroud)
版画
event_A
event_B
Run Code Online (Sandbox Code Playgroud)
编辑:好的,您的问题标题似乎具有误导性
“我想要一个在其构造函数中带有两个参数的类。第一个可以是 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;
};
Run Code Online (Sandbox Code Playgroud)
这适用于任何类型,对于第一个参数: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?");
}
Run Code Online (Sandbox Code Playgroud)
如果您删除最后一行的注释,您实际上会得到一个编译器错误。
C++2003 不允许字符串文字
ISO/IEC 14882-2003 §14.1:
14.1 模板参数
非类型模板参数应具有以下(可选的 cv 限定)类型之一:
— 整数或枚举类型,
— 指向对象或指向函数的指针,
— 对对象的引用或对函数的引用,
— 指向成员的指针。
ISO/IEC 14882-2003 §14.3.2:
14.3.2 模板非类型参数
非类型、非模板模板参数的模板参数应为以下之一:
— 整数或枚举类型的整数常量表达式;或者
— 非类型模板参数的名称;或者
— 具有外部链接的对象或函数的地址,包括函数模板和函数模板 ID,但不包括非静态类成员,表示为 & 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
Run Code Online (Sandbox Code Playgroud)
—结束示例] —结束说明]
而且看起来在即将到来的 C++0X 中它不会改变,请参阅当前草案 14.4.2 Template non-type arguments。
您不能直接将字符串文字作为模板参数传递。
但是您可以接近:
template<class MyString = typestring_is("Hello!")>
void MyPrint() {
puts( MyString::data() );
}
...
// or:
MyPrint<typestring_is("another text")>();
...
Run Code Online (Sandbox Code Playgroud)
您需要的只是这里的一个小头文件。
备择方案:
定义一个全局char const *
变量并将其作为指针传递给模板。(这里)
缺点:需要模板参数列表之外的其他代码。如果您需要指定字符串文字“ inline”,则不合适。
使用非标准语言扩展名。(这里)
缺点:不能保证与所有编译器一起使用。
使用BOOST_METAPARSE_STRING
。(这里)
缺点:您的代码将取决于Boost库。
使用char的可变参数模板参数包,例如str_t<'T','e','s','t'>
。
这就是以上解决方案在后台为您执行的操作。
使用代理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;
}
Run Code Online (Sandbox Code Playgroud)