首页 > 解决方案 > 在现代 C++ 之前,在没有 constexpr if 的情况下选择性地执行代码

问题描述

我想编写一些线程包装器,并且我需要使用线程参数 as void *,因为我使用的是非 C++11 线程库。我偶然发现了一个问题并准备了一个最小的工作示例。这是代码:

#include <iostream>

namespace chops {
    template <typename T, typename U>
    struct is_same {
        static const bool value = false;
    };

    template<typename T>
    struct is_same<T, T> {
        static const bool value = true;
    };
}

template <typename Functor, typename T>
typename Functor::return_type fun_wrapper(T const& arg) {
    Functor f;
    typename Functor::return_type ret = f(arg);
    return ret;
}

struct hello_world {
    void operator()(int count) {
        while(count--)
            std::cout << "hello, world!\n";
    }
    typedef void return_type;
};

struct is_even {
    bool operator()(int x) {
        if(!(x % 2))
            return true;
        else
            return false;
    }
    typedef bool return_type;
};

int main() {
    //fun_wrapper<hello_world>(3);
    fun_wrapper<is_even>(3);
} 

在这里,如果你想在 main 中执行注释掉的行,它不会编译,因为它想实例化一个包含如下行的模板

void x = //something

所以我给自己写了一个is_same类型特征,并且只想在Functor::return_type不为空的情况下执行该代码。我想要效果:

if constexpr(!is_same<Functor::return_type, void>::value) {
    typename Functor::return_type res = f(arg);
    return ret;
} else {
    f(arg);
}

由于我不能使用现代 C++,但只能使用 C++17,我似乎找不到方法。我不知道如何用 SFINAE 之类的东西达到类似的效果。

PS:请注意,这是一个人为的示例,可以进行一些修改,但在我的实际程序中,我需要创建一个对象,Functor::return_type如果它不是 void。因此,请不要在您的答案中删除该行。所以,不只是使用return f(arg).

标签: c++templatesc++03

解决方案


最简单的方法是创建两个重载,一个用于何时Functor::return_typevoid,一个用于何时不是。您所要做的就是重新实现std::enable_if(例如在命名空间中chops):

template <bool expr, typename T = void>
struct enable_if
{
};

template <typename T>
struct enable_if<true, T>
{
    typedef T type;
};

然后将单个fun_wrapper函数模板替换为两个受约束的模板:

template <typename Functor, typename T>
typename chops::enable_if<
    !chops::is_same<typename Functor::return_type, void>::value,
    typename Functor::return_type>::type 
fun_wrapper(T const& arg) {
    Functor f;
    typename Functor::return_type ret = f(arg);
    return ret;
}

template <typename Functor, typename T>
typename chops::enable_if<chops::is_same<typename Functor::return_type, void>::value>::type 
fun_wrapper(T const& arg) {
    Functor f;
    f(arg);
}

wandbox上的现场演示。


推荐阅读