使sfinae适用于推导出返回类型的函数?

Vin*_*ent 2 c++ lambda sfinae template-meta-programming c++14

请考虑以下代码:

// -------------------------------------------------------------------------- //
// 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;
}
// -------------------------------------------------------------------------- //
Run Code Online (Sandbox Code Playgroud)

该实用程序apply在可以编译时将参数应用于参数,否则它什么都不做.该机制依赖于sfinae.然而,对于函数,其返回类型从主体推导,如gh在上述例子中,SFINAE失败.在C++ 14中是否有一种聪明的方法来修改apply实用程序,这样即使对于从主体推断出返回类型的函数,它也会强制使用sfinae?

注意:我想制作gh工作f,意思是调用apply应该调用void版本.

Yak*_*ont 6

SFINAE只能捕获替代错误.

调用函数时的一些错误不能是替换错误.这些包括解析函数体时发生的错误.

C++明确选择将这些错误排除在触发SFINAE之外,而是触发硬错误,使编译器不必编译任意函数体来确定是否发生SFINAE.由于SFINAE必须在重载解析期间完成,这使得C++编译器的重载解析代码更容易.

如果您希望您的代码对SFINAE友好,则不能使用lambdas g或者h.