2017-07-03 46 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