Передача const char * в качестве аргумента шаблона
Почему вы не можете передавать литературные строки здесь? Я сделал это с очень небольшим обходом.
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();
}
Ответы
Ответ 1
Потому что это не будет полезной утилитой. Поскольку они не являются допустимой формой аргумента шаблона, в настоящее время он не работает.
Предположим, что они работают. Поскольку у них нет необходимости иметь один и тот же адрес для одного и того же значения, вы получите разные экземпляры, даже если в коде есть одно и то же строковое литераловое значение.
lols<"A"> n;
// might fail because a different object address is passed as argument!
lols<"A"> n1 = n;
Вы можете написать плагин для текстового редактора, который заменяет строку разделенным запятыми списком символов и обратно. С вариационными шаблонами вы могли бы "решить" эту проблему таким образом, в некотором роде.
Ответ 2
Возможно, но аргумент шаблона должен иметь внешнюю связь, что исключает использование литералов и смягчает полезность этого.
Пример, который у меня есть:
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_>();
Ответ 3
Вот как я это делаю. Мне гораздо больше смысла:
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>();
}
Ответ 4
Это работает для классов и, IMO, полезно. Реализация быстрая и грязная, но ее легко сделать более чистой:
#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(); }
Выход:
Правда! Ложь! Правда! Ложь!
Ответ 5
Хороший вопрос, подумал, я бы бросил свою шляпу в кольцо... Я думаю, вы можете передавать указатели на статические переменные в качестве аргументов шаблонного типа. С С++ 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;
}