3

I want to use the implementation of std::pow (from cmath) in some cases, and in other cases, I want to use myspace::pow.

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

The different cases are determined by a template parameter.

template <typename T>
void myFunction()
{
    auto val = pow(2.1,3);
    /* ... */
}

If T == double, I want val to be calculated with std::pow. If T == mydouble, I want val to be calculated with myspace::pow. Now, I have a lot of lines like auto val = pow(2.1,3);, and I would like to avoid to check for the type of T for each line of code.

struct mydouble { /* ... */ };
myFunction<double>(); // uses std::pow
myFunction<mydouble>(); // uses myspace::pow

I've been breaking my head over this, but I can't find a solution. Any suggestions?

mfnx
  • 2,894
  • 1
  • 12
  • 28
  • You could check T's type with a constexpr if and std::is_same::value. – nada Aug 08 '19 at 11:48
  • @nada ok, I have to edit the question to be more clear. I'd like to avoid checking the type for each command. – mfnx Aug 08 '19 at 11:49
  • I think you can do it using `std::enable_if` – sklott Aug 08 '19 at 11:51
  • Or overload pow for mydouble. – nada Aug 08 '19 at 11:51
  • @MFnx with constexpr if or std::enable_if you're checking types at compile time, so no runtime performance penalty, if that's what you're concerned about. – nada Aug 08 '19 at 11:53
  • @nada Could you give me an example? I don't want to check the type each time I call the pow function. – mfnx Aug 08 '19 at 11:55
  • 1
    What's wrong with normal function overloading? Just write your `pow` as `mydouble pow(mydouble val, unsigned exp) ...` (**do this in the same namespace that `mydouble` is in**) and everything should work perfectly fine. – Max Langhof Aug 08 '19 at 11:56
  • @MFnx The type check can be done _inside_ your `pow` implementation with `constexpr if` and/or `std::enable_if`. – Max Langhof Aug 08 '19 at 11:57
  • @MFnx As I said, the type is *not* checked each time the pow function is called, with mentioned methods it's checked at compile time. – nada Aug 08 '19 at 11:58
  • You can do something like `using mypow = std::enable_if, std::pow>::value;` and similar to `mydouble`, then just use `mypow()`. – sklott Aug 08 '19 at 11:59
  • 2
    Do you know of ADL (argument dependent lookup)? – L. F. Aug 08 '19 at 12:04
  • @L.F. no, I'll look that up. – mfnx Aug 08 '19 at 12:06
  • 2
    Possible duplicate of [What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")?](https://stackoverflow.com/questions/8111677/what-is-argument-dependent-lookup-aka-adl-or-koenig-lookup) – L. F. Aug 08 '19 at 12:07
  • Someone could provide an answer with enable_if? – mfnx Aug 08 '19 at 12:45

2 Answers2

2

There are several solutions I could suggest.


Class Dispatcher (C++11)

Just implement a functor which picks the correct implementation in accordance with its templated type:

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);
  } 
};

And you can use it as follows:

template <typename T>
void myFunction(const T& t) {
  using Pow = PowerAdapter<T>;

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

Complete Code Example


Argument-Dependent Lookup (C++98)

If your class MyDouble is in the same namespace of your pow then you can just use this C++ rule:

[...] function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.

So the code:

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

will select the proper pow in accordance with the namespace of T. Note that, in case of double, you want to select the pow from math.h in the global namespace (unqualified name lookup).

Complete Code Example

I personally don't like this approach because it hides the selection mechanism and it's more difficult to extend.


if constexpr (C++17)

You can pick a proper branch at compile time. Wrap your select logic into a proper function (or functor). Something like:

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);
  }
}

Complete Code Example

BiagioF
  • 9,368
  • 2
  • 26
  • 50
0

Using Argument-dependent lookup you can achieve this easily

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
}
Andreas DM
  • 10,685
  • 6
  • 35
  • 62