I want to multiplay a std::complex<T> by a double, assuming that T operator*(const T &t, double d) is defined. Since I need to do this for 3 different types T, i tried to write a template function for the operator. Here's an example with T=float.
#include <iostream>
#include <complex>
template <typename T>
std::complex<T> operator*(const std::complex<T> &cd, double d) {
return std::complex<T>(cd.real() * d, cd.imag());
}
int main() {
std::complex<float> cf(1.0, 1.0);
std::complex<double> cd(1.0, 1.0);
double d = 2.0;
std::cout << cf * d << std::endl;
std::cout << cd * d << std::endl;
}
This gives the compiler error
error: ambiguous overload for ‘operator*’ (operand types are ‘std::complex<double>’ and ‘double’)
The reason is clear, since for T=double my overload clashes with the implementation in <complex>. First casting the right hand side to a T (i.e. cf * float(d) in the example above) is not an option, since that would introduce significant overhead for some of my datatypes.
Is there any way I can tell the compiler that it should ignore my overload for T=double?
Is there any way I can tell the compiler that it should ignore my overload for T=double?
You might use SFINAE:
template <typename T>
std::enable_if_t<!std::is_same<double, T>::value, std::complex<T>>
operator*(const std::complex<T> &cd, double d) {
return std::complex<T>(cd.real() * d, cd.imag());
}
but your implementation is not coherent with regular operator*.
A safer way would be to introduce your own type to wrap double, something like:
struct MyWrapper { double d; };
template <typename T>
std::complex<T> operator*(const std::complex<T> &cd, MyWrapper d) {
return std::complex<T>(cd.real() * d.d, cd.imag());
}
std::complex already defines an operator * in the form of
template< class T >
std::complex<T> operator*( const std::complex<T>& lhs, const T& rhs);
This conflicts with your own operator * since both functions resolve to taking a std::complex<double> and a double.
That means you really only need to define an operator * for std::vector<float> and a double so you can change your overload to
std::complex<float> operator*(const std::complex<float> &cd, double d) {
return std::complex<float>(cd.real() * d, cd.imag());
}
And then
std::cout << cf * d << std::endl;
std::cout << cd * d << std::endl;
will work.
If you want to keep the overload a template function you can use SFINAE to make it not compile for the case when you have a std::complex<double> by using
template <typename T, std::enable_if_t<!std::is_same_v<double, T>, bool> = true>
std::complex<T> operator*(const std::complex<T> &cd, double d) {
return std::complex<T>(cd.real() * d, cd.imag());
}
Related
In a project I'm working on I have a templated function similar to this where all of the arguments should be of type T
#include <iostream>
template<typename T> bool aWithinBOfC(T a, T b, T c)
{
return std::abs(a - c) < b;
}
the issue I'm having is it won't compile if all of the arguments are not of the same type but it seems reasonable that it should implicitly cast similar types to the one with the highest resolution before evaluation. Is there any way to get a call like this to be valid?
int main()
{
double a{1.2};
double b{1.4};
float c{0.1f};
std::cout << aWithinBOfC(a, b, c) << std::endl;
}
Something along these lines, perhaps:
template<typename T>
bool aWithinBOfCImpl(T a, T b, T c) {
/* actual implemenattion */
}
template <typename ... Args>
auto aWithinBOfC(Args... args) {
return aWithinBOfCImpl<std::common_type_t<Args...>>(args...);
}
Demo
You don’t need implicit conversions at the call site. The compiler will implicitly convert the types to the largest one in the expression in the return statement.
template <class T, class U, class V>
bool aWithinBOfC(T a, U b, V c) {
return std::abs(a - c) < b;
}
I have such code:
boost::optional<double> result = _ind1.Value() / _ind2.Value();
Each arg is boost::optional<double> too:
boost::optional<double> Value() {
return value;
}
Errors are:
Error 1 error C2676: binary '/' : 'boost::optional<T>' does not define this operator or a conversion to a type acceptable to the predefined operator
2 IntelliSense: no operator "/" matches these operands
operand types are: boost::optional<double> / boost::optional<double>
I understand that it seems that division is just not defined. I expect result to be boost::none if any of two arguments is none - otherwise I want it to be normal double division. Should I just write this myself?
Of course such a simple operation as division of doubles is supported.
But you aren't trying to divide doubles. You're trying to divide boost::optional<double>s which is a whole different story.
If you want, you can define a division operator for this. It might look like (untested):
template<typename T>
boost::optional<T> operator/(const boost::optional<T>& a, const boost::optional<T>& b)
{
if(a && b) return *a / *b;
else return boost::optional<T>();
}
In C++11 (code courtesy of Yakk):
template<class T,class U> struct divide_result {
typedef typename std::decay<decltype(std::declval<T>()/std::declval<U>())>::type;
};
template<class T, class U> using divide_result_t=typename divide_result<T,U>::type;
template<typename T,typename U>
boost::optional<divide_result_t<T,U>> operator/(const boost::optional<T>& a, const boost::optional<U>& b)
{
if(a && b) return *a / *b;
else return boost::none;
}
I used a template because now it's also good for int, float, etc.
I have written the following function to apply various math operations to each element of a vector:
namespace MYFUNCTION
{
template<class T>
std::vector<T> eop(const std::vector<T> &v1, T (*f)(T))
{
std::vector<T> v2(v1.size());
for(int ii = 0; ii < v1.size(); ii++)
{
v2[ii] = (*f)(v1[ii]);
}
return v2;
}
}
I have also overloaded the cosh() function for std::vector parameters:
namespace MYFUNCTION
{
template<class T>
std::vector<T> cosh(const std::vector<T> v1)
{
return eop(v1,static_cast<T (*)(T)>(&std::cosh));
}
}
If I use this function for type double every thing is fine. If I use std::complex<double> instead I get a compiler error.
std::vector<double> a(2);
a[0] = 1.0;
a[1] = 2.0;
std::cout << MYFUNCTION::cosh(a) << std::endl; // Works fine.
std::vector<std::complex<double> > b(2);
b[0] = 1.0 + std::complex<double>(0.0,1.0);
b[1] = 2.0;
std::cout << MYFUNCTION::cosh(b) << std::endl; // Compiler error.
The compiler error is:
error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘std::complex<double> (*)(std::complex<double>)’
EDIT:
This is the what the cosh function looks like in complex.h:
template<class T> complex<T> cosh (const complex<T>& x);
This is the what the cosh function looks like in cmath.h:
double cosh (double x);
I have included both complex.h and cmath.h.
Since std::cosh for std::complex<T> is a function template, &std::cosh doesn't make sense to the compiler because std::cosh is not a function, it is a template of family of functions. You need to write another overload to handle this case:
#include <complex> //it is where std::cosh<T> is defined
template<class T>
std::vector<std::complex<T>> cosh(std::vector<std::complex<T>> const & v1)
{
typedef std::complex<T> cosh_type( std::complex<T> const &);
return eop(v1, static_cast<cosh_type*>(&std::cosh<T>) );
}
By the way, pass the argument by reference to avoid unnecessary copies.
Hope that helps.
i wrote a template class that should work for double and std::complex. as it is suppose to be, all my methods are in the .hpp file. all but one. i had to specialize a method because at some place i have to compute the square of a double or the norm of a std::complex. more explicitly for the "double specialization" (A):
double a(2.0);
double b(0.0);
b = a*a;
for the "complex specialization" (B):
std::complex<double> a(2.0,3.0);
double b(0.0);
b = std::norm(a);
my questions are :
is there a way to avoid theses specializations by using a function that works for both double and complex ? (because the std::norm works only for complex...)
or the only solution is to cast the double a of the specialization (A) into a complex and then use only the specialization (B) as a general template (working for both double and complex)?
You can minimise the divergent case by introducing your own function as a square/norm wrapper:
template <typename T>
double square_or_norm(T x);
template<>
inline double square_or_norm(double x) { return x * x; }
template <>
inline double square_or_norm(std::complex<double> x) { return norm(x); }
Then, use it inside the function which needs it:
template <typename T>
T computation(T x) {
return some_code_with(x, square_or_norm(x));
}
You could define two function template overloads (when it comes to function templates, overloading is usually preferable to specialization) called compute_norm(), one accepting std::complex and one accepting unconstrained types. The unconstrained template would invoke operator *, while the constrained template would invoke std::norm().
#include <complex>
template<typename T>
double compute_norm(T t)
{ return t * t; }
template<typename T>
double compute_norm(std::complex<T> const& t)
{ return std::norm(t); }
Then, your generic code that can work both with a double and with a complex<double> would call compute_norm():
#include <iostream>
template<typename T>
void foo(T&& t)
{
// ...
double n = compute_norm(std::forward<T>(t));
std::cout << n << std::endl;
// ...
}
For instance, the following program:
int main()
{
double a(2.0);
foo(a);
std::complex<double> c(2.0, 3.0);
foo(c);
}
Will output:
4
13
Here is a live example.
If you have a conforming standard library, there is an overload of std::norm for floating point types:
26.4.9 Additional overloads [cmplx.over]
The following function templates shall have additional overloads:
arg norm
conj proj
imag real
The additional overloads shall be sufficient to ensure:
If the argument has type long double, then it is effectively cast to complex.
Otherwise, if the argument has type double or an integer type, then it is effectively cast to complex<
double>.
Otherwise, if the argument has type float, then it is effectively cast to complex.
This should work (and does on gcc 4.7.2)
#include <complex>
#include <iostream>
int main()
{
std::complex<double> c {1.5, -2.0};
double d = 2.5;
std::cout << "|c| = " << std::norm(c) << '\n'
<< "|d| = " << std::norm(d) << '\n';
}
Why not just use function overloading?
double myNorm(double);
double myNorm(std::complex<double>);
double myNorm(double x) {
return x * x;
}
double myNorm(std::complex<double> x) {
return std::norm(x);
}
You can put the implementation in your .cpp or (when inlined) in your header file.
For some strange reason, I can't get the template arguments in this one piece of code to implicitly cast to a compatible type.
#include <type_traits>
template <typename T, unsigned D>
struct vec;
template <>
struct vec<float, 2> {
typedef float scalar;
static constexpr unsigned dimension = 2;
float x, y;
float& operator[] (unsigned i) { return (&x)[i]; }
float const& operator[] (unsigned i) const { return (&x)[i]; }
};
template <typename L, typename R>
struct add;
template <typename L, typename R, unsigned D>
struct add<vec<L, D>, vec<R, D>> {
typedef vec<L, D> left_type;
typedef vec<R, D> right_type;
typedef vec<typename std::common_type<L, R>::type, D> return_type;
add(left_type l, right_type r)
: left(l),
right(r)
{}
operator return_type() const
{
return_type result;
for (unsigned i = 0; i < D; ++i)
result[i] = left[i] + right[i];
return result;
}
left_type left;
right_type right;
};
template <typename L, typename R, unsigned D>
add<vec<L, D>, vec<R, D>>
operator+(vec<L, D> const& lhs, vec<R, D> const& rhs)
{
return {lhs, rhs};
}
int main()
{
vec<float, 2> a, b, c;
vec<float, 2> result = a + b + c;
}
Fails with:
prog.cpp: In function 'int main()':
prog.cpp:55:36: error: no match for 'operator+' in 'operator+ [with L = float, R = float, unsigned int D = 2u](((const vec<float, 2u>&)((const vec<float, 2u>*)(& a))), ((const vec<float, 2u>&)((const vec<float, 2u>*)(& b)))) + c'
So if I'm correct, the compiler should see the code in the main function as this:
((a + b) + c)
compute a + b
cast the result of a + b from add<...> to vec<float, 2> using the conversion operator in add<...>
compute (a + b) + c
But it never does the implicit cast. If I explicitly cast the result of (a + b) to a vec, the code works fine.
I'm going to side-step your actual problem and instead make a recommendation: Rather than writing all of this complicated boilerplate from scratch, have a look at Boost.Proto, which has taken care of all the tricky details for you:
Proto is a framework for building Domain Specific Embedded Languages in C++. It provides tools for constructing, type-checking, transforming and executing expression templates. More specifically, Proto provides:
An expression tree data structure.
A mechanism for giving expressions additional behaviors and members.
Operator overloads for building the tree from an expression.
Utilities for defining the grammar to which an expression must conform.
An extensible mechanism for immediately executing an expression template.
An extensible set of tree transformations to apply to expression trees.
See also the library author's Expressive C++ series of articles, which more-or-less serve as an (excellent) in-depth Boost.Proto tutorial.
Most conversions are not used during template argument deduction.
You rely on template argument deduction when you call your operator+ overload: it is only callable where both arguments are of type vec<...>, but when you try to call it the left-hand argument is of type add<...>. The compiler is not able to figure out that you really mean for that overload to be called (and it isn't allowed to guess), hence the error.