基于模板值的条件编译?

Rob*_*yce 5 c++ templates

提出的问题: 在模板中键入条件

非常相似,但原始问题并未得到完全回答。

#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;
}
Run Code Online (Sandbox Code Playgroud)

这不会编译,我也没有期望。这样的事情可能吗?基于模板值,我希望一些代码可以编译,而其他则不需要。在这里,“ double”没有称为“ Plus”的方法,而“ AA”类不会覆盖“ +”运算符。考虑操作的细微语义时,操作符重载并不总是可取的,因此我正在寻找一种替代方法。我宁愿进行#ifdef的工作(如参考问题中所述的进行真正的条件编译),但要基于模板值。

Wor*_*mer 9

由于 C++17 有静态 if 被称为 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;
}
Run Code Online (Sandbox Code Playgroud)


Pra*_*han 5

你想要的是一个静态的 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>);
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我想我最喜欢这个解决方案。静态 if 将是理想的方法。你看,这是一个更大问题的简化版本,其中我有 4 个专业化需要使用代码的一种变体,还有 4 个专业化需要使用代码的第二个变体。这个解决方案让我在代码库中为每个变体都有一个实现。 (2认同)

bol*_*lov 3

double doit(AA &t) {
  return t.Plus(t);;
}
template<class T> double doit(T &t) {
  return t + t;
}
Run Code Online (Sandbox Code Playgroud)

您的代码不起作用,因为如果模板被推断为AA那么t + t体内的格式不正确。另一方面, ifT推导出 as doublethent.Plus(t)就变得格式错误。

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

doIt(a)实例doIt化为T = double

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

doIt(aa)实例doIt化为T = AA

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

您应该避免专门化函数模板,因为函数会过载。您可以阅读 Herb Sutter 这篇优秀的文章:为什么不专门化函数模板?