【发布时间】:2017-09-10 19:04:55
【问题描述】:
我正在尝试找到一种方法来减少一些语法“噪音”,而无需借助宏。对于以下代码:
struct base { base() = delete; };
struct tag1 final : private base
{
static constexpr const char* name = "tag1";
};
template <typename T> std::string name() { return T::name; }
// ...
int main()
{
const std::string name1(name<tag1>());
return 0;
}
摆脱一些static constexpr const char*(更不用说其他)语法会很好,因为重复tag2、tag3等会很烦人。另外,唯一的部分所有真正有趣的是tag1,其余的是“噪音”。直接的解决方案是使用宏:
#define MAKE_TAG(tag_name) struct tag_name final : private base { \
static constexpr const char* name = #tag_name; }
MAKE_TAG(tag2);
// ...
const std::string name2(name<tag2>());
基于宏的MAKE_TAG(tag2); 语法已经消除了所有“噪音”,使tag2 非常突出。宏的另一个好处是tag_name 可以轻松转换为字符串文字,从而防止复制粘贴错误。
一个“明显”的可能解决方案可能是通过name as a template argument
template<const char* name> base { ... };
struct tag3 final : private base<"tag3"> {};
但那是not supported by C++。下面answer 中的一个巧妙解决方法是使用可变参数模板:
template<char... S> struct base { base() = delete;
static std::string name() { return{ S... }; } };
struct tag4 final : base<'t', 'a', 'g', '4'> { };
template <typename T> std::string name() { return T::name(); }
这确实减少了很多噪音,但需要写't', 'a', 'g', '4' 而不是"tag4"。运行时解决方案相当简洁
struct base {
const std::string name;
base(const std::string& name) : name(name) {} };
struct tag5 final : base { tag5() : base("tag5") {} };
template <typename T> std::string name() { return T().name; }
但这并不完全令人满意,因为 tag5 现在可以被实例化,理想情况下这是没有意义的。还有,现在tag5要写三遍,不是很DRY。
有没有办法进一步简化(即减少打字)上面的代码? ...不使用宏?
【问题讨论】:
-
请注意
std::string没有constexpr构造函数,您将无法在constexpr上下文中调用name。 -
我不清楚为什么需要
static constexpr const char* name = "tag1";以外的任何东西?所有其他样板的目的是什么?