元编程:动态声明一个新结构



是否可以动态声明一个新类型(空结构,或没有实现的结构(?

例如

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, "");

"手动"解决方案是

template <class> struct Tag;
using A = Tag<struct TagA>;
using B = Tag<struct TagB>;
using C = Tag<struct TagC>;

甚至

struct A;
struct B;
struct C;

但是对于模板/元,一些神奇make_new_type()功能会很好。

既然有状态元编程格式不正确,这样的事情可能吗?

你几乎可以使用你想要的语法

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__>());

这是有效的,因为每个 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);

在 C++20 中:

using A = decltype([]{}); // an idiom
using B = decltype([]{});
...

这是惯用代码:这就是人们在 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__>;

匿名命名空间是最重要的位。不将 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;

另一种方法是手动链接类型,并让编译器静态验证链接是否正确完成,如果不这样做,则出现错误。所以它不会很脆(假设魔法成功了(。

像这样:

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>;

只需要一点点魔法就可以确保类型为 A2 和 C2 的行不会编译。这种魔力在C++11中是否可能是另一回事。

我知道

...他们是蒸馏邪恶的...但在我看来,这是一个旧的 C 风格宏的作品

#include <type_traits>
#define  newType(x) 
struct type_##x {}; 
using x = type_##x;
newType(A)
newType(B)
newType(C)
int main ()
 {
   static_assert(!std::is_same<A, B>::value, "");
   static_assert(!std::is_same<B, C>::value, "");
   static_assert(!std::is_same<A, C>::value, "");
 }

最新更新