C++ 将常量char*作为模板参数传递
为什么不能在这里传递文本字符串?我做了一个很小的变通C++ 将常量char*作为模板参数传递,c++,string,templates,C++,String,Templates,为什么不能在这里传递文本字符串?我做了一个很小的变通 template<const char* ptr> struct lols { lols() : i(ptr) {} std::string i; }; class file { public: static const char arg[]; }; decltype(file::arg) file::arg = __FILE__; // Getting the right type declaration
template<const char* ptr> struct lols {
lols() : i(ptr) {}
std::string i;
};
class file {
public:
static const char arg[];
};
decltype(file::arg) file::arg = __FILE__;
// Getting the right type declaration for this was irritating, so I C++0xed it.
int main() {
// lols<__FILE__> hi;
// Error: A template argument may not reference a non-external entity
lols<file::arg> hi; // Perfectly legal
std::cout << hi.i;
std::cin.ignore();
std::cin.get();
}
模板结构lols{
lols():i(ptr){}
std::字符串i;
};
类文件{
公众:
静态常量字符参数[];
};
decltype(文件::arg)文件::arg=__文件_;;
//为此获取正确的类型声明是令人恼火的,因此我使用了C++0xE。
int main(){
//哈哈哈;
//错误:模板参数不能引用非外部实体
lols hi;//完全合法
std::cout因为这不是一个有用的实用程序。因为它们不是模板参数的允许形式,所以它目前不起作用
让我们假设它们可以工作。因为对于使用的相同值,它们不需要具有相同的地址,所以即使代码中有相同的字符串文本值,也会得到不同的实例化
lols<"A"> n;
// might fail because a different object address is passed as argument!
lols<"A"> n1 = n;
lolsn;
//可能会失败,因为另一个对象地址作为参数传递!
lols n1=n;
您可以为文本编辑器编写一个插件,用逗号分隔的字符文本列表替换字符串,然后返回。使用可变模板,您可以“解决”在某种程度上,这个问题是这样的。这是可能的,但模板参数必须具有外部链接,这就排除了使用文本字符串,并降低了执行此操作的实用性
我举的一个例子是:
template<const char* name, const char* def_value=empty_>
struct env : public std::string
{
env()
{
const char* p = std::getenv(name);
assign(p ? p : def_value);
}
};
extern const char empty_[] = "";
std::string test = env<empty_>();
模板
结构环境:公共标准::字符串
{
环境()
{
const char*p=std::getenv(名称);
分配(p?p:def_值);
}
};
extern const char empty_[]=“”;
std::string test=env();
我就是这样做的。这对我来说更有意义:
struct MyString { static const std::string val; }
const std::string MyString::val = "this is your string";
template<typename T>
void func()
{
std::cout << T::val << std::endl;
}
void main()
{
func<MyString>();
}
struct MyString{static const std::string val;}
const std::string MyString::val=“这是您的字符串”;
模板
void func()
{
std::cout这适用于类,而且,依我看,这很有用。实现速度快且不干净,但很容易变得更干净:
#include <stdio.h>
#include <string.h>
struct TextTag { const char *text; };
template <const TextTag &TRUE, const TextTag &FALSE>
struct TextTaggedBool
{
const char *GetAsText() const { return m_value ? TRUE.text: FALSE.text; }
void SetByText(const char *s) { m_value = !strcmp(s, TRUE.text); }
bool m_value;
};
class Foo
{
public:
void method()
{
m_tbool.SetByText("True!"); printf("%s\n", m_tbool.GetAsText());
m_tbool.SetByText("False!"); printf("%s\n", m_tbool.GetAsText());
m_tbool.m_value = true; printf("%s\n", m_tbool.GetAsText());
m_tbool.m_value = false; printf("%s\n", m_tbool.GetAsText());
}
private:
static constexpr TextTag TrueTag = { "True!" };
static constexpr TextTag FalseTag = { "False!" };
TextTaggedBool<TrueTag, FalseTag> m_tbool;
};
void main() { Foo().method(); }
#包括
#包括
结构TextTag{const char*text;};
模板
结构TextTaggedBool
{
const char*GetAsText()const{返回m_值?TRUE.text:FALSE.text;}
void SetByText(const char*s){m_value=!strcmp(s,TRUE.text);}
布尔m_值;
};
福班
{
公众:
void方法()
{
m_tbool.SetByText(“True!”);printf(“%s\n”,m_tbool.GetAsText());
m_tbool.SetByText(“False!”);printf(“%s\n”,m_tbool.GetAsText());
m_tbool.m_value=true;printf(“%s\n”,m_tbool.GetAsText());
m_tbool.m_value=false;printf(“%s\n”,m_tbool.GetAsText());
}
私人:
静态constexpr TextTag TrueTag={“True!”};
静态constexpr TextTag False tag={“False!”};
TextTaggedBool m_tbool;
};
void main(){Foo().method();}
输出:
真的!
假的!
真的!
False!问得好,我想我会把我的帽子扔进戒指里……我想你可以把指向静态变量的指针作为非类型模板参数传递。从C++20来看,这似乎不会是一个问题……在那之前,这里有一些便宜的宏让它工作
template <const char *Name, typename T>
struct TaggedValue {
static constexpr char const *name{Name};
T value;
friend ostream &operator<<(ostream &o, const TaggedValue &a) {
return o << a.name << " = " << a.value;
}
};
#define ST(name, type)\
const char ST_name_##name[]{#name};\
using name = TaggedValue<ST_name_##name,type>;
ST(Foo, int);
ST(Bar, int);
ST(Bax, string);
int main() {
cout << Foo{3} << endl;
cout << Bar{5} << endl;
cout << Bax{"somthing"} << endl;
}
模板
结构标记值{
静态constexpr char const*name{name};
T值;
friend ostream&operatorconst char file::arg[]=\uuuuu file\uuuuu;
这应该允许您返回到C++03:)。@Kenny:我试过了。编译器抛出错误。@Dead:Odd.g++编译很好(带-pedantic)@Kenny:令人恼火的是,我一直认为这是不可能的。现在我有了它,我似乎无法让它做任何有趣或有用的事情。请注意,如果在命名空间范围内,您将需要extern const char arg[]=\uu FILE\uuu;
来提供数组外部链接(默认情况下,const对象具有内部链接)。只是回避了一个问题,为什么他们不给他们相同的地址。@DeadMG因为字符串文字“A”在某些上下文中可能是立即数,但根本没有地址?@SlashV我知道已经有一段时间了,但您是否愿意对此进行扩展?我对解释也有点感兴趣。@Zadirion..还有一段时间。鉴于模板参数需要获取其地址,编译器需要为字符串提供唯一的地址文字“A”。这对编译器来说是一个不必要的限制。文字“A”可能是内存中某个地方的常量(并且有一个地址),但编译器可能有多个副本,因此地址不是唯一的,或者文字“A”可能是机器代码指令的“立即”操作数,因此不在任何位置的数据内存中,因此根本没有地址。@SlashV:这是完全错误的。该语言已经要求编译器在许多上下文中合并全局变量(例如内联函数)。强制他们将字符串文本集合在一起并没有多少困难。至于immediates,字符串文本必须具有程序持续时间存储,因此将字符串文本的内容存储在immediate中已经是非法的……除了您不应该从namespace std