基于模板值的条件编译?

时间:2015-01-21 20:09:44

标签: c++ templates

提出的问题: Type condition in template

非常相似,但最初的问题还没有得到很好的解答。

#include "stdafx.h"
#include <type_traits>


class AA {
public:
    double a;

    double Plus(AA &b) {
        return a + b.a;
    }
};

template<class T> double doit(T &t) {
    if (std::is_same<T, AA>::value)
        return t.Plus(t);
    else
        return t + t;
}

int _tmain(int argc, _TCHAR* argv[])
{
    double a;
    AA aa;

    doit(a);
    doit(aa);

    return 0;
}

这不编译,我也没想到。这样的事情可能吗?基于模板值,我希望编译一些代码,而不是其他代码。在这里,&#39; double&#39;没有一个名为&#34; Plus&#34;的方法。和班级&#34; AA&#34;不会覆盖&#39; +&#39;运营商。在考虑操作的细微语义时,操作符重载并不总是令人满意的,因此我正在寻找替代方法。我更喜欢做#ifdef(真正的条件编译,如参考问题所示),但是基于模板值。

5 个答案:

答案 0 :(得分:3)

重载?

template<class T>
double doit(T &t) {
    return t + t;
}

double doit(AA &t) {
    return t.Plus(t);
}

明确的专业化也是可能的,虽然多余:

template<class T>
double doit(T &t) {
    return t + t;
}

template<>
double doit<>(AA &t) {
    return t.Plus(t);
}

答案 1 :(得分:2)

double doit(AA &t) {
  return t.Plus(t);;
}
template<class T> double doit(T &t) {
  return t + t;
}

您的代码无效,因为如果模板推断为AA,那么正文中的t + t格式不正确。另一方面,如果T被推断为double,那么t.Plus(t)就会变得格格不入。

为了更好地了解发生的事情: 为每个模板类型实例化一个模板,使用。

doIt(a)使用doIt实例化T = double

double doIt<double>(double &t) {
  if (false)
     return t.Plus(t);  // <-- syntax error
  else
    return t + t;
}

doIt(aa)使用doIt实例化T = AA

double doIt<AA>(AA &t) {
  if (true)
    return t.Plus(t);
  else 
    return t + t;   // <-- syntax error
}

您应避免专门化功能模板,因为功能过载。你可以阅读这篇优秀的Herb Sutter文章:Why Not Specialize Function Templates?

答案 2 :(得分:2)

你想要的是静态的if。 C ++没有它。有很多方法可以解决它,没有一个像本机支持一样好。除了其他两个答案中指定的方法之外,您还可以尝试标记调度。

template<class T> double doitImpl(T &t, std::true_type) {
    return t.Plus(t);
}

template<class T> double doitImpl(T &t, std::false_type) {
    return t+t;
}

template<class T> double doit(T &t) {
    return doitImpl(t, std::is_same<T, AA>);
}

答案 3 :(得分:2)

从C ++ 17开始,如果调用if-constexpr,则会出现静态。以下编译好,因为clang-3.9.1和gcc-7.1.0,最新的MSVC编译器19.11.25506也可以使用选项/ std:c ++ 17处理得很好。

template<class T> double doit(T &t) {
    if constexpr (std::is_same_v<T, AA>)
        return t.Plus(t);
    else
        return t + t;
}

答案 4 :(得分:0)

此代码编译并运行:

#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.hpp>

using namespace boost;

class AA {
public:
    double a;

    AA Plus(AA &b) {
        AA _a;
        _a.a = a + b.a;
        return _a;
    }
};


template<class T>
typename disable_if<is_floating_point<T>, T >::type
doit(T &t) {
    return t.Plus(t);
}


template<class T>
typename enable_if<is_floating_point<T>, T >::type
doit(T &t) {
    return t+t;
}

int _tmain(int argc, _TCHAR* argv[])
{
    double a;
    AA aa;

    doit(a);
    doit(aa);

    return 0;
}