【发布时间】:2021-06-25 15:59:43
【问题描述】:
我正在使用 C++17。我编写了以下代码,应该使用 SFINAE 来测试 lambda 是否可编译(lambda 在语法上总是正确的,但可能是不可编译的,例如由于正文中没有使用某些方法):
#include <type_traits>
#include <sstream>
#include <iostream>
#include <tuple>
template <typename ... Ts>
struct Types {
using types = std::tuple<Ts...>;
template <size_t I>
using type = std::tuple_element_t<I, types>;
};
template <typename F, typename Enable = void, typename ... Ts>
struct Compilable : std::false_type {};
template <typename F, typename ... Ts>
struct Compilable<F,
std::void_t<decltype((*(F*)0)(Types<Ts...>{}))>, Ts...>
: std::true_type {};
template <typename ... Ts, typename F>
bool constexpr Comp(F const & f) {
return Compilable<F, void, Ts...>::value;
}
template <typename T>
void Test() {
std::cout << Comp<T>([](auto Ts){
typename decltype(Ts)::template type<0> * p = 0;
std::stringstream ss; ss << (*p); }) << std::endl;
}
struct X {};
int main() {
Test<int>();
Test<X>();
}
我希望由于 SFINAE 会默默排除不可编译的特化,但它会引发编译错误(对于第二个 Test<X>() 案例,第一个测试编译):
<source>:30:34: error: invalid operands to binary expression
('std::stringstream' (aka 'basic_stringstream<char>') and
'typename decltype(Ts)::type<0>' (aka 'X'))
std::stringstream ss; ss << (*p); }) << std::endl;
我做错了什么?我是否错误地使用了 SFINAE 机制?实现上述代码的正确方法应该是什么?
【问题讨论】:
-
如果你不引用/调用失败的对象,SFINAE 就可以工作。你叫它。
-
@S.M.但我正在使用
decltype()的调用结果,仅派生结果类型,因此实际调用从未完成。 -
没有办法将位于函数或函数模板的 body 中的东西问“这东西编译了吗?”。粗略地说,SFINAE 的工作方式是尝试实例化一堆模板(重载或特化),并拒绝不产生可编译 header(不是正文)的实例化。您不能尝试使用本身无效的参数来实例化模板。
-
只有函数类型及其模板参数类型的immediate context中的无效类型和表达式才会导致推演失败。