C++:替代“std::is_fundamental”的方法?

5
在模板类的函数中,我试图区分基本类型和其他类型。
在 c++ 11 中,您可以使用以下方法:
if(std::is_fundamental<T>::value)
{
    // Treat it as a primitive
}
else
{
    //Treat it otherwise
}

如果我错误了,而这不仅适用于 C++11,请纠正我。

在早期版本的 C++ 中是否有替代方法?

2个回答

8
您可以这样在C++03中使用Boost的类型特性
#include  <boost/type_traits/is_fundamental.hpp>

...

if(boost::is_fundamental<T>::value)
{
    // Treat it as a primitive
}
else
{
    //Treat it otherwise
}

我猜这个方法也适用于C++98。


2

使用这段代码可能会遇到问题。如果您需要区分不同的类型特征,则必须在编译时而不是运行时进行。根据您执行的操作,您的if语句中的两个分支中的一个可能无法编译。因此,最好转发到专门的函数:

void operation_impl(boost::true_type /*other params*/) {
  // Treat it is primitive 
}

void operation_impl(boost::false_type /*other params*/) {
  // Treat it otherwise
}

template<class T>
void operation(/* params*/) {
  operation_impl(boost::is_fundamental<T>::type() /*other params*/);
}

使用这种实现技术,只需要编译使用的分支(即正确的分支)。

编辑:

以下是一些额外的信息。解决此问题与模板的实例化有关。我从is_fundamental切换到is_array以显示操作可能失败的情况。

让我们从第一个示例开始:

template <class T>
void fun(T t) {
    if(boost::is_array<T>::value)
    {
        std::cout << "true" << std::endl;
    }
    else
    {
        std::cout << "false" << std::endl;
    }
}

void f(int i) {
    fun(i);
}

这段代码能够编译和运行,编译器会发现只有if语句的一个分支会被使用,因此会将另一个分支作为未使用的代码删除。

在我的第二个例子中,如果我使用数组操作,我将会执行一些操作:

template<class T>
void fun(T& t) {
    if(boost::is_array<T>::value)
    {
        std::cout << t[0];
    }
    else
    {
        std::cout << t;
    }
}

void f(int i) {
    fun(i);
}

现在它不能编译。原因是int作为模板参数时,t[0]是不合法的。您无法使用此运行时语句来在编译时区分代码中所需的类型属性(在此示例中为数组的属性和t [0]的使用)。在第三个示例中,我们将通过函数重载在编译时进行区分:
template<class T>
void fun_impl(boost::true_type, T& t) {
    std::cout << t[0];
}

template<class T>
void fun_impl(boost::false_type, T& t) {
    std::cout << t;
}

template<class T>
void fun(T& t) {
    fun_impl(typename boost::is_array<T>::type(),t);
}

void f(int i) {
    fun(i);
}

在这里,is_array<T>::type 可以是 true_type 或者 false_type。这个结果被用作在编译时选择正确的 fun_impl 重载函数的选择器,只有被选中的重载函数才会被实例化和编译。
通常这种技术被用来在编译时选择最佳的实现方式,这种实现方式只有当类型具有某些属性时才能被编译。
第二次编辑:
如果语言中包含了 static if,那么这个情况当然会发生改变。

你可以详细说明一下我可能会在另一种方法中遇到什么问题吗?或者您能添加一个解释的参考吗?我不理解您写的内容。 - Subway
谢谢!感谢您的详细解释。不过我还有一个问题:据我理解,您的观点是为了让代码编译通过,并且避免编译不必要的代码。 假设我的代码已经编译通过,使用第一种方法在运行时是否会遇到实际问题(例如意外行为)? - Subway
@Subway 我认为编译器将 boost::is_fundamental<T>::value 视为常量并删除未使用的代码,因此没有运行时开销和 UB。方法是让它编译通过。const 值成员用于与 std::enable_if(作为整数模板参数)一起使用,当然也用于演示(如打印该值)。我认为,对于其他任何目的,您应该通过函数重载进行操作。 - Jan Herrmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接