Tomo Bogdanovic
Tomo Bogdanovic

Reputation: 23

Template Cast-Operator specification

I'm setting up an Average class and fell over following problem:

template <typename T, typename Total>
class Average
{
public:
  Average(...){ ... }

...

operator double() const
{
  if (num_samples_ == 0)
  {
    return 0;
  }
  else
  {
    return static_cast<double>(total_) / num_samples_;
  }
}

operator T() const
{
  if (num_samples_ == 0)
  {
    return 0;
  }
  else
  {
    return round<T>(total_ / num_samples_);
  }
}
...
};

When I create the instance of Average like this:

Average<double, double> m_avg;

I get the error, that the operator double is already defined.

I understand that the operator is defined 2 times now. But how do I solve the problem? I want that the operator double() is called when double is casted and all other types call T()

Upvotes: 0

Views: 135

Answers (3)

Jarod42
Jarod42

Reputation: 217135

In C++2a, you may discard method thanks to requires:

operator T() const requires (!std::is_same<double, T>::value) {/*code*/}

Before that SFINAE on method (making it template) or (partial) specialization of the class might solve the issue.

Upvotes: 2

W.F.
W.F.

Reputation: 13988

To answer your explicit question - you could make your first overload template and disable it for all other types than double by using of SFINAE mechanism. The template function has a lower priority than non-template overloads so it wouldn't match in case when T==double.

Exemplary code:

#include <iostream>
#include <type_traits>

template <class T>
struct Foo {
    template <class D, std::enable_if_t<std::is_same_v<D, double>, int> = 0>
    operator D() {
        std::cout << "double version" << std::endl;
        return 0.0;
    }

    operator T() {
        std::cout << "general version" << std::endl;
        return T{};
    }
};

int main() {
    Foo<double> fd;
    (double)fd;
    Foo<int> fi;
    (double)fi;
}

Output:

general version 
double version

(Live demo)

Note that if it need to be pre-c++17 use typename std::enable_if<std::is_same<D, double>::value>::type instead of std::enable_if_t<std::is_same_v<D, double>, int>.

Upvotes: 2

Daniel Langr
Daniel Langr

Reputation: 23497

Another solution not based on SFINAE:

#include <type_traits>

template <typename T>
struct X {
  using T_ = typename std::conditional<std::is_same<T, double>::value, void, T>::type;
  operator double() { return double{}; }
  operator T_() { return T_{}; }
};

int main() {
  X<int> xi;
  X<double> xd;
}

Live demo: https://wandbox.org/permlink/vT4DTCWiEOkPWlhu

Upvotes: 0

Related Questions