我想要一个在其构造函数中包含两个参数的类。第一个可以是int,double或float,所以<typename T>
,第二个总是字符串文字“my string”,所以我想const char * const
。
任何人都可以给我一些可编译的代码,它声明了一个简单的类模板,并声明了该类的对象吗?
由于
答案 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();
}
答案 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;
};
这适用于任何类型,第一个参数: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不允许使用字符串文字
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的小标题文件。
<强>备选方案:强>
答案 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
最后,EWG决定取消先前批准的提案,以允许在非类型模板参数中使用字符串文字,这是因为允许非类型模板参数中的类类型(刚刚被批准)的更通用的功能就足够了替代。 (这是上次会议的一次更改,当时我们似乎都希望两者兼而有之。)主要区别在于,您现在必须将字符数组包装到一个结构中(请考虑fixed_string或类似的结构),并将其用作模板参数类型。 (P0424的用户定义文字部分仍在继续,并对允许的模板参数类型进行了相应的调整。)
对于C ++ 17 if constexpr
:if / 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;