2017-05-30 13 views
34

一个我已经幸运地遇到是constexpr counter,又名状态元编程。正如在帖子中提到的,它似乎在C++ 14下是合法的,我想知道C++ 17有什么变化吗?是有状态的元编程不健全(还)?我最亲爱的/邪恶的发明

以下是主要立足岗位

template <int N> 
struct flag 
{ 
    friend constexpr int adl_flag(flag<N>); 
    constexpr operator int() { return N; } 
}; 

template <int N> 
struct write 
{ 
    friend constexpr int adl_flag(flag<N>) { return N; } 
    static constexpr int value = N; 
}; 

template <int N, int = adl_flag(flag<N>{})> 
constexpr int read(int, flag<N>, int R = read(0, flag<N + 1>{})) 
{ 
    return R; 
} 

template <int N> 
constexpr int read(float, flag<N>) 
{ 
    return N; 
} 

template <int N = 0> 
constexpr int counter(int R = write<read(0, flag<0>{}) + N>::value) 
{ 
    return R; 
} 

的实施和我们use it

static_assert(counter() != counter(), "Your compiler is mad at you"); 

template<int = counter()> 
struct S {}; 

static_assert(!std::is_same_v<S<>, S<>>, "This is ridiculous"); 

这顺便说一下,是一个直接的矛盾Storing States in C++ Metaprogramming?

+0

如何'读(0,标志 {})'不会导致一个无限循环?文字0会导致它调用第一个重载('int'优先于'float'),这会自然地再次调用它。什么是终止条件? –

+1

@NicolBolas通过SFINAE时,''的过载int'读(0,标志 {})'不能被称为对于足够大一些'N',因为我们还没有定义'adl_flag(标志)',因此,'浮动'重载将被调用。对于完整的解释,链接的文章写得很好。 –

+2

还请注意David Krauss在相应的[std-discussion](https://groups.google.com/a/isocpp.org/d/msg/std-discussion/M6aJMH_ewoM/eAaBooYw-MsJ)线程中指出的缺陷,菲利普承诺在第四篇文章中谈到,但从未做过。 – Columbo

回答

31

CWG active issue 2118

定义在模板的朋友的功能,然后引用该函数后提供捕获和检索元编程状态的手段。这种技术是神秘的,应该做成不合格的。从五月

注意,2015年会议:

CWG一致认为,这种技术应该是病态的,但禁止它们的机制尚未确定。

这仍然是一个活跃的问题,至少现在在C++ 17中什么都不会改变。虽然确定这种禁止机制时,可以追溯为DR。