kay*_*kay 14 c++ templates metaprogramming stateful compile-time-constant
是否可以即时声明一个新类型(一个空的struct或没有实现的struct)?
例如
constexpr auto make_new_type() -> ???;
using A = decltype(make_new_type());
using B = decltype(make_new_type());
using C = decltype(make_new_type());
static_assert(!std::is_same<A, B>::value, "");
static_assert(!std::is_same<B, C>::value, "");
static_assert(!std::is_same<A, C>::value, "");
Run Code Online (Sandbox Code Playgroud)
一个“手动”解决方案是
template <class> struct Tag;
using A = Tag<struct TagA>;
using B = Tag<struct TagB>;
using C = Tag<struct TagC>;
Run Code Online (Sandbox Code Playgroud)
甚至
struct A;
struct B;
struct C;
Run Code Online (Sandbox Code Playgroud)
但是对于模板/ meta,一些魔术make_new_type()功能会很好。
有状态的元编程格式不正确,这样的事情是否可能呢?
Nat*_*ica 22
您几乎可以得到想要使用的语法
template <size_t>
constexpr auto make_new_type() { return [](){}; }
using A = decltype(make_new_type<__LINE__>());
using B = decltype(make_new_type<__LINE__>());
using C = decltype(make_new_type<__LINE__>());
Run Code Online (Sandbox Code Playgroud)
这是可行的,因为每个lambda表达式都会产生唯一的类型。因此,对于其中的每个唯一值,<>您将获得不同的函数,该函数返回不同的闭包。
如果你介绍一个宏可以摆脱不必键入的__LINE__一样
template <size_t>
constexpr auto new_type() { return [](){}; }
#define make_new_type new_type<__LINE__>()
using A = decltype(make_new_type);
using B = decltype(make_new_type);
using C = decltype(make_new_type);
Run Code Online (Sandbox Code Playgroud)
Rei*_*ica 18
在C ++ 20中:
using A = decltype([]{}); // an idiom
using B = decltype([]{});
...
Run Code Online (Sandbox Code Playgroud)
这是惯用的代码:这就是用C ++ 20编写“给我一个独特的类型”的方式。
在C ++ 11中,最清晰,最简单的方法是使用__LINE__:
namespace {
template <int> class new_type {};
}
using A = new_type<__LINE__>; // an idiom - pretty much
using B = new_type<__LINE__>;
Run Code Online (Sandbox Code Playgroud)
匿名名称空间是最重要的部分。不将new_type类放在匿名名称空间中是一个严重的错误:这样,类型在翻译单元之间将不再是唯一的。在您计划发货前15分钟,将会发生各种欢笑:)
这扩展到C ++ 98:
namespace {
template <int> class new_type {};
}
typedef new_type<__LINE__> A; // an idiom - pretty much
typedef new_type<__LINE__> B;
Run Code Online (Sandbox Code Playgroud)
另一种方法是手动链接类型,并让编译器静态验证链接是否正确完成,如果不正确,则抛出错误。因此它不会很脆弱(假设魔术成功了)。
就像是:
namespace {
struct base_{
using discr = std::integral_type<int, 0>;
};
template <class Prev> class new_type {
[magic here]
using discr = std::integral_type<int, Prev::discr+1>;
};
}
using A = new_type<base_>;
using A2 = new_type<base_>;
using B = new_type<A>;
using C = new_type<B>;
using C2 = new_type<B>;
Run Code Online (Sandbox Code Playgroud)
仅需一点点魔术就可以确保A2和C2类型的行不会编译。在C ++ 11中这种魔术是否可能是另一回事。