2017-07-03 45 views
5

我想了解尚未合并到标准中的Concepts Lite TS。我对概念体中的短路不连续行为感到困惑。C++ Concepts Lite:概念体中的短路

这里是一个小例子:

#include <type_traits> 
#include <iostream> 

template <typename T, typename ... Ts> concept bool myconcept = 
(sizeof...(Ts) == 0) || (std::is_same_v<T, std::common_type_t<Ts...>>); 

template <typename ... Ts> 
void myfunc(Ts ... args) requires myconcept<int, Ts...> { 
    (... , (std::cout << args << std::endl)); 
} 

int main() { 
    myfunc(); 
    return 0; 
} 

用gcc 7.1和-fconcepts编译,给出了错误:

error: cannot call function 'void myfunc(Ts ...) requires myconcept<int, Ts ...> [with Ts = {}]' 

在这个例子中,std::common_type_t<Ts...>不存在,因为该结构std::common_type<Ts...>不有一个成员type如果Ts = {}。不过,我想这应该编译,因为cppereference.com对concepts and constraints文档指出

Disjunctions are evaluated left to right and short-circuited (if the left constraint is satisfied, template argument deduction into the right constraint is not attempted).

由于sizeof...(Ts) == 0满意,模板参数推导不应该试图在第二约束和要求myconcept<int, Ts...>应该感到满意。

奇怪的是,直接将要求进入函数声明导致程序编译:

#include <type_traits> 
#include <iostream> 

template <typename ... Ts> 
void myfunc(Ts ... args) requires (sizeof...(Ts) == 0) || (std::is_same_v<int, std::common_type_t<Ts...>>) { 
    (... , (std::cout << args << std::endl)); 
} 

int main() { 
    myfunc(); 
    return 0; 
} 

是否有此行为的一个很好的解释? 谢谢。

+0

“概念精简版TS是尚未被合并到标准的”我在哪里可以找到这些信息?我最后的信息是没有被接受... – Klaus

回答

2

出现在cppreference上的外行人的解释是正确的。从n4674 draft选择措辞相当清楚,以及:

A conjunction is a constraint taking two operands. A conjunction of constraints is satisfied if and only if both operands are satisfied. The satisfaction of a conjunction’s operands are evaluated left-to-right; if the left operand is not satisfied, template arguments are not substituted into the right operand, and the constraint is not satisfied. […]

(从17.10.1.1逻辑操作[temp.constr.op]§2)由于所有的措辞是准确的设定我们是如何从概念去原子约束的连接或分离的模板很长,我们将坚持外行的解释。

Is there a good explanation for this behavior? Thanks.

在撰写本文时,GCC实现的概念非常具有实验性。作为一种变通方法,您可以重构问题的一部分变成自己的理念:

template<typename T, typename... Ts> 
concept bool refactored = std::is_same_v<T, std::common_type_t<Ts...>>; 

template<typename T, typename... Ts> 
concept bool myconcept = sizeof...(Ts) == 0 || refactored<T, Ts...>; 

Coliru demo