使sfinae适用于推导返回类型的函数? [英] Making sfinae works for functions with deduced return type?

查看:50
本文介绍了使sfinae适用于推导返回类型的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

  // ---------------- -------------------------------------------------- -------- // 
//预处理程序
#include< array>
#include< vector>
#include< utility>
#include< iostream>
#include< type_traits>
// -------------------------------------------- ------------------------------ //



// -------------------------------------------------- ------------------------ //
//如果可以调用
template<则调用不带参数的函数。
类F,
类... Args,
类= decltype(std :: declval< F>()())
>
decltype(auto)apply(F&& f)
{
std :: cout<< apply(F&& f)<< std :: endl ;
return std :: forward< F>(f)();
}

//如果可以调用
template<
类F,
类Arg,
类... Args,
类= decltype(std :: declval< F>()(
std :: declval< ; Arg>(),std :: declval< Args>()...
))
>
decltype(auto)apply(F&& f,Arg&& arg,Args&& ... args)
{
std :: cout<<应用F& f,Arg& arg,Args& ... args)<<< std :: endl;
return std :: forwardF(f)(
std :: forward< Arg(arg),
std :: forward< Args>(args)...
);
}

//如果无法使用给定参数调用函数,则不执行任何操作
template<
F类,
类... Args
>
void apply(F& f,Args& ... args)
{
std :: cout< apply(F& f,Args&& ; ... args)<< std :: endl;
}
// --------------------------------------- ----------------------------------- //



// --------------------------------------------- ----------------------------- //
//主函数
int main(int argc,char * argv [])
{
//初始化
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();
};

//测试
apply(f,std :: vector< double>()); //-> sfinae作品
apply(g,std :: vector< double>()); //-> sfinae作品
apply(h,std :: vector< double>()); //-> sfinae工作
apply(f,std :: array< double,1>()); //-> sfinae工作
// apply(g,std :: array< double,1>()); -> sfinae失败,不编译
// apply(h,std :: array< double,1>()); -> sfinae失败,不编译

//返回
返回0;
}
// --------------------------------------- ----------------------------------- //

实用程序 apply 将可编译的函数应用于自变量,否则不执行任何操作。该机制依赖于sfinae。但是,对于从其主体推断出返回类型的函数,例如上例中的 g h ,sfinae失败。在C ++ 14中是否有一种聪明的方法来修改 apply 实用程序,以便即使对于从其主体推断出返回类型的函数,它也会强制sfinae插入? / p>

注意:我想制作 g h 用作 f ,这意味着 apply 的调用应调用 void 版本。

解决方案

SFINAE只能捕获替换错误。



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



C ++明确选择从触发SFINAE的过程中排除这些错误,而触发硬错误以使编译器不必编译任意函数的主体以确定SFINAE是否发生。由于必须在重载解析期间完成SFINAE,因此这使得C ++编译器的重载解析代码更加容易。



如果您希望代码对SFINAE友好,则不能使用lambdas。例如 g h


Consider the following code:

// -------------------------------------------------------------------------- //
// 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;
}
// -------------------------------------------------------------------------- //

The utility apply, applies a function to arguments when it can compile, otherwise it does nothing. The mechanism relies on sfinae. However, for function whose return type is deduced from the body, like g and h in the above example, sfinae fails. Would there be a smart way in C++14 to modify the apply utility so that it forces sfinae to kicks in even for functions whose return type is deduced from the body?

Note: I would like to make g and h work as f, meaning that the call of apply should call the void version.

解决方案

SFINAE can only catch substitution errors.

Some errors when calling a function cannot be substitution errors. These include errors that happen when you parse the body of a function.

C++ explicitly chose to exclude these errors from triggering SFINAE and instead trigger hard errors to free compilers from having to compile bodies of arbitrary functions to determine if SFINAE occurs. As SFINAE must be done during overload resolution, this makes the overload resolution code of a C++ compiler easier.

If you want your code to be SFINAE friendly, you cannot use lambdas like g or h.

这篇关于使sfinae适用于推导返回类型的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆