请考虑以下代码:
// -------------------------------------------------------------------------- //
// Preprocessor
#include <array>
#include <vector>
#include <utility>
#include <iostream>
#include <type_traits>
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// Calls a function without arguments if it can be called
template <
class F,
class... Args,
class = decltype(std::declval<F>()())
>
decltype(auto) apply(F&& f)
{
std::cout<<"apply(F&& f)"<<std::endl;
return std::forward<F>(f)();
}
// Calls a function with arguments if it can be called
template <
class F,
class Arg,
class... Args,
class = decltype(std::declval<F>()(
std::declval<Arg>(), std::declval<Args>()...
))
>
decltype(auto) apply(F&& f, Arg&& arg, Args&&... args)
{
std::cout<<"apply(F&& f, Arg&& arg, Args&&... args)"<<std::endl;
return std::forward<F>(f)(
std::forward<Arg>(arg),
std::forward<Args>(args)...
);
}
// Does nothing if the function cannot be called with the given arguments
template <
class F,
class... Args
>
void apply(F&& f, Args&&... args)
{
std::cout<<"apply(F&& f, Args&&... args)"<<std::endl;
}
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// Main function
int main(int argc, char* argv[])
{
// Initialization
auto f = [](auto&& x) -> decltype(std::forward<decltype(x)>(x).capacity()) {
return std::forward<decltype(x)>(x).capacity();
};
auto g = [](auto&& x) -> decltype(auto) {
return std::forward<decltype(x)>(x).capacity();
};
auto h = [](auto&& x) {
return std::forward<decltype(x)>(x).capacity();
};
// Test
apply(f, std::vector<double>()); // -> sfinae works
apply(g, std::vector<double>()); // -> sfinae works
apply(h, std::vector<double>()); // -> sfinae works
apply(f, std::array<double, 1>());// -> sfinae works
//apply(g, std::array<double, 1>()); -> sfinae fails, does not compile
//apply(h, std::array<double, 1>()); -> sfinae fails, does not compile
// Return
return 0;
}
// -------------------------------------------------------------------------- //
实用程序apply
在可以编译时将参数应用于参数,否则它什么都不做。该机制依赖于sfinae。但是,对于从主体推导出返回类型的函数,如上例中的g
和h
,sfinae会失败。在C ++ 14中是否有一种聪明的方法可以修改apply
实用程序,这样即使对于从正文中推断出返回类型的函数,它也会强制执行sfinae?
注意:我希望将g
和h
视为f
,这意味着apply
的调用应该调用void
版本。< / p>
答案 0 :(得分:6)
SFINAE只能捕获替代错误。
调用函数时的一些错误不能是替换错误。这些包括解析函数体时发生的错误。
C ++明确选择将这些错误排除在触发SFINAE之外,而是触发硬错误,使编译器不必编译任意函数体来确定是否发生了SFINAE。由于SFINAE必须在重载解析期间完成,这使得C ++编译器的重载解析代码更容易。
如果您希望代码对SFINAE友好,则不能使用g
或h
等lambda。
答案 1 :(得分:1)
对于apply
,您的SFINAE工作得很好。
至于为什么f
有效,这是因为:
这是一个模板,
它已在替换阶段失败。
这意味着它拥有自己的SFINAE,以及f
默认的do-nothing被调用(对于array
),如预期的那样。
在C ++ 14中是否有一种聪明的方法来修改apply 实用程序,以便它... ...
不,apply
已经做到了所有这一切。
至于为什么g()
和h()
不起作用,他们会产生
当你用没有的东西调用它们时会出现硬错误
有capacity
。
一个实用功能你(尝试)在之后应用即可
不删除那个硬错误。
解决这个问题的唯一方法是“双重打击”SFINAE,
就像你在f()