根据模板参数使用一个命名空间或另一个命名空间

3

我希望在某些情况下使用cmath库中的std::pow实现,在其他情况下,我想使用myspace::pow

namespace myspace
{
    template <typename T>
    T pow(T val, unsigned exp)
    {
        if (exp == 0) return 1;
        return val*pow(val,exp-1);
    }
}

不同的情况由模板参数确定。
template <typename T>
void myFunction()
{
    auto val = pow(2.1,3);
    /* ... */
}

如果 T == double,我希望使用 std::pow 计算 val。如果 T == mydouble,我希望使用 myspace::pow 计算 val。现在,我有很多像这样的代码行:auto val = pow(2.1,3);,我想避免每行代码都检查 T 的类型。
struct mydouble { /* ... */ };
myFunction<double>(); // uses std::pow
myFunction<mydouble>(); // uses myspace::pow

我已经为此烦恼了很长时间,但是我找不到解决办法。有什么建议吗?


@nada 好的,我需要编辑问题以使其更清晰。我想避免为每个命令检查类型。 - mfnx
1
普通函数重载有什么问题吗?只需将您的 pow 写成 mydouble pow(mydouble val, unsigned exp) ...mydouble 所在的相同命名空间中执行此操作),一切都应该完美地工作。 - Max Langhof
2
你知道 ADL(参数依赖查找)吗? - L. F.
@L.F. 不,我会查一下的。 - mfnx
显示剩余9条评论
2个回答

2
我可以提出几个解决方案。

类分发器(C++11)

只需实现一个函数对象,根据其模板类型选择正确的实现:

template <typename T>
struct PowerAdapter {
  auto operator()(const T& arg, const T& exp) const {
    return std::pow(arg, exp);
  }
};

template <>
struct PowerAdapter<myspace::MyDouble> {
  auto operator()(const myspace::MyDouble& arg, unsigned exp) const {
    return myspace::pow(arg, exp);
  } 
};

您可以按照以下方式使用它:
template <typename T>
void myFunction(const T& t) {
  using Pow = PowerAdapter<T>;

  auto val = Pow{}(t, t);
  // ...
}

完整代码示例


参数相关的查找(C++98)

如果你的类 MyDouble 和你的 pow 函数在同一个命名空间中,那么你可以使用这个 C++ 规则:

[...] 在常规未限定名称查找所考虑的作用域和命名空间之外,函数名也会在其参数的命名空间中查找

因此,下面的代码:

template <typename T>
void myFunction(const T& t) {
  pow(t, 12);
}

将会根据 T 的命名空间选择适当的pow。请注意,在 double 的情况下,您希望在全局命名空间(未限定名称查找)中选择来自 math.hpow
完整代码示例:Complete Code Example 个人而言,我不喜欢这种方法,因为它隐藏了选择机制并且更难扩展。

if constexpr(C++17)

您可以在编译时选择适当的分支。 将您的选择逻辑封装到一个适当的函数(或函数对象)中。例如:

template <typename T, typename U>
auto PowerAdapter(const T& val, const U& exp) {
  if constexpr (std::is_same_v<T, myspace::MyDouble>) {
    return myspace::pow(val, exp);
  } else {
    return std::pow(val, exp);
  }
}

完整代码示例


0

使用参数依赖查找,您可以轻松实现这一点。

namespace ns
{
    template <typename T>
    auto pow(T val, unsigned exp)
    {
        using std::pow;
        std::cout << __FUNCTION__ << '\n';
        return pow(val, exp);
    }
}

struct mydouble
{
    double d;
};

mydouble pow(mydouble val, unsigned exp)
{
    std::cout << __FUNCTION__ << '\n';
    return val;
}

int main() 
{
    ns::pow(mydouble{ 3.14 }, 2); // runs pow
    ns::pow(4, 2);                // runs std::pow
}

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