18

C++14将具有可以根据返回值推断返回类型的函数。

auto function(){
    return "hello world";
}

我可以将此行为应用于通过返回类型习语为 SFINAE使用enable_if的函数吗?

例如,让我们考虑以下两个函数:

#include <type_traits>
#include <iostream>

//This function is chosen when an integral type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_integral<T>::value>::type {
    std::cout << "integral" << std::endl;
    return;
}

//This function is chosen when a floating point type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_floating_point<T>::value>::type{
    std::cout << "floating" << std::endl;
    return;
}

int main(){

  function(1);    //prints "integral"
  function(3.14); //prints "floating"

}

如您所见,使用 SFINAE 通过返回类型习语选择正确的函数。但是,这些都是 void 函数。的第二个参数enable_if默认设置为void。这将是相同的:

//This function is chosen when an integral type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_integral<T>::value, void>::type {
    std::cout << "integral" << std::endl;
    return;
}

//This function is chosen when a floating point type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_floating_point<T>::value, void>::type{
    std::cout << "floating" << std::endl;
    return;
}

我可以对这两个函数做些什么,以便通过返回值推断出它们的返回类型?

gcc 4.8.2(使用--std=c++1y

4

4 回答 4

13

std::enable_if不必在返回类型中,从 C++11 开始,它可以是模板参数的一部分。

所以你的等效函数可以是(或者,嗯,有这种效果的东西):

enum class enabler_t {};

template<typename T>
using EnableIf = typename std::enable_if<T::value, enabler_t>::type;

//This function is chosen when an integral type is passed in
template<class T, EnableIf<std::is_integral<T>>...>
auto function(T t) {
    std::cout << "integral" << std::endl;
    return;
}

//This function is chosen when a floating point type is passed in
template<class T, EnableIf<std::is_floating_point<T>>...>
auto function(T t) {
    std::cout << "floating" << std::endl;
    return;
}

也可以是函数中的参数:

//This function is chosen when an integral type is passed in
template<class T>
auto function(T t, EnableIf<std::is_integral<T>>* = nullptr) {
    std::cout << "integral" << std::endl;
    return;
}

//This function is chosen when a floating point type is passed in
template<class T>
auto function(T t, EnableIf<std::is_floating_point<T>>* = nullptr) {
    std::cout << "floating" << std::endl;
    return;
}

这将保留自动类型扣除和 SFINAE。

于 2013-12-20T18:40:22.613 回答
6

std::enable_if可以是返回类型、函数参数或模板参数。如果使用返回类型或模板参数,会出现函数重定义错误,因此需要std::enable_if作为函数参数使用:

#include <type_traits>
#include <iostream>

template<class T, typename = typename std::enable_if<std::is_integral<T>::value, void>::type>
auto function(T t, typename std::enable_if<std::is_integral<T>::value, void>::type* dummy = nullptr) {
    std::cout << "integral" << std::endl;
    return 0;
}

//This function is chosen when a floating point type is passed in
template<class T, typename = typename std::enable_if<std::is_floating_point<T>::value, void>::type>
auto function(T t, typename std::enable_if<std::is_floating_point<T>::value, void>::type* dummy = nullptr) {
    std::cout << "floating" << std::endl;
    return 0.0f;
}

int main() 
{
    auto ret = function(0); // integral
    auto ret2 = function(0.0f); // floating
    std::cout << std::boolalpha << std::is_integral<decltype(ret)>::value << std::endl; // true
    std::cout << std::is_floating_point<decltype(ret2)>::value << std::endl; // true
}
于 2013-12-20T18:45:41.487 回答
3

在@user1508519 的答案行中,我们可以从方法中删除 enable_if 参数,并将其仅保留为模板参数。enable_if<false>我们依赖于不定义的事实type,所以enable_if<false>::type,不存在的,是 SFINAE 的一个很好的工具——在方法签名中,其中包括模板参数。

没有必要在方法本身中实际使用这个模板参数!

因此:

template<class T,
typename std::enable_if<std::is_integral<T>::value>::type* dummy = nullptr>
auto function(T t) {
    std::cout << "integral" << std::endl;
    return 0;
}

// This function is chosen when a floating point type is passed in
template<class T, 
typename std::enable_if<std::is_floating_point<T>::value>::type* dummy = nullptr>
auto function(T t) {
    std::cout << "floating" << std::endl;
    return 0.0f;
}

int main() {
    auto ret = function(0); // integral
    auto ret2 = function(0.0f); // floating
    cout << std::boolalpha;
    cout << std::is_integral<decltype(ret)>::value << endl; // true
    cout << std::is_floating_point<decltype(ret2)>::value << endl; // true
}

输出

integral
floating
true
true
于 2016-06-17T15:11:32.133 回答
0

如其他地方所述std::enable_if,可用于形成任一返回类型;函数参数;或模板参数。

但是,后两种方法的缺点是它们会改变相关函数或对象的签名。std::enable_if另一方面,使用at 返回类型会使函数和模板参数计数保持不变。

随着 C++11 中 lambda 返回类型的自动推断(可能扩展到 C++14 中的普通函数),如果有一种技术可以同时推断返回类型,那将是理想的;std::enable_if在返回类型上使用。让你的蛋糕吃掉 - 几乎。唉,这似乎是目前不可能的。

于 2014-04-14T20:19:27.123 回答