その場で新しい型(空の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, "");
_
「手動」ソリューションは
_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()
関数がいいでしょう。
ステートフルメタプログラミングが不正な形式 になったときに、そのようなことが可能になりますか?
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で可能かどうかは別の話です。
使用したい構文をほぼ得ることができます
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__>());
すべてのラムダ式が一意の型になるため、これは機能します。そのため、<>
の一意の値ごとに、異なるクロージャーを返す異なる関数を取得します。
マクロを導入すると、__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スタイルのマクロのための作品だと私には思えます
#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, "");
}