(Sử dụng g++ 7.0
cốp xe.)đánh giá không phù hợp cho `lambdas constexpr` trong các mẫu giữa 'static_assert`,` nếu constexpr (...) `và` biến constexpr`
Do sau "loại-to -giá trị gói" tiện ích ...
template <typename T>
struct type_wrapper { using type = T; };
// "Wraps" a type into a `constexpr` value.
template <typename T>
constexpr type_wrapper<T> type_c{};
... tôi tạo ra các chức năng sau đây để kiểm tra tính hợp lệ của một biểu thức:
template <typename TF>
constexpr auto is_valid(TF)
{
return [](auto... ts) constexpr
{
return std::is_callable<TF(typename decltype(ts)::type...)>{};
};
}
Chức năng is_valid
có thể được sử dụng như sau:
// Evaluates to `true` if `some_A.hello()` is a valid expression.
constexpr auto can_add_int_and_float =
is_valid([](auto _0) constexpr -> decltype(_0.hello()){})
(type_c<A>);
// Evaluates to `true` if `some_int + some_float` is a valid expression.
constexpr auto can_add_int_and_float =
is_valid([](auto _0, auto _1) constexpr -> decltype(_0 + _1){})
(type_c<int>, type_c<float>);
Nó cũng có thể được sử dụng bên static_assert
...
static_assert(is_valid([](auto _0) constexpr -> decltype(_0.hello()){})
(type_c<A>));
... và bên trong if constexpr
:
if constexpr(
is_valid([](auto _0) constexpr -> decltype(_0.hello()){})
(type_c<A>)) { /* ... */ }
Tuy nhiên, khi is_valid
được sử dụng bên trong một mẫu chức năng (đi qua các thông số mẫu như type_c
giá trị), một cái gì đó kỳ lạ xảy ra:
static_assert(is_valid(/*...*/))
công trình đúng cách.constexpr auto x = is_valid(/*...*/)
hoạt động bình thường.if constexpr(is_valid(/*...*/)
không thể biên dịch.
// Compiles and works as intended.
template <typename T0, typename T1>
void sum_ok_0(T0, T1)
{
static_assert(
is_valid([](auto _0, auto _1) constexpr
-> decltype(_0 + _1){})(type_c<T0>, type_c<T1>)
);
}
// Compiles and works as intended.
template <typename T0, typename T1>
void sum_ok_1(T0, T1)
{
constexpr auto can_sum =
is_valid([](auto _0, auto _1) constexpr
-> decltype(_0 + _1){})(type_c<T0>, type_c<T1>);
if constexpr(can_sum) { }
}
// Compile-time error!
template <typename T0, typename T1>
void sum_fail_0(T0, T1)
{
if constexpr(is_valid([](auto _0, auto _1) constexpr
-> decltype(_0 + _1){})(type_c<T0>, type_c<T1>)) { }
}
Lỗi:
In function 'void sum_fail_0(T0, T1)':
64:95: error: expression '<lambda>' is not a constant expression
if constexpr(is_valid([](auto _0, auto _1) constexpr -> decltype(_0 + _1){})(type_c<T0>, type_c<T1>)) { }
Tại sao điều này thất bại trong việc biên dịch chỉ dành cho các trường hợp if constexpr(is_valid(/*...*/))
? Điều này không phù hợp với static_assert
và constexpr auto x = /*...*/
.
Đây có phải là lỗi trong việc triển khai if constexpr
không?
Bạn đã phát minh lại [std :: is_callable] (http://en.cppreference.com/w/cpp/types/is_callable). –
@SamVarshavchik: không còn nữa :) –
Chắc chắn trông giống như một lỗi. –