Understanding code duplication in template specializations of std::complex<T> - c++

I was looking at the <complex> implementations of the C++ Standard Library. I noticed for all of the current GNU, LLVM and MSVC implementations, there is a huge amount of code duplication for template specializations for types float double and long double, but I don't know why.
Take the MSVC code at https://github.com/microsoft/STL/blob/main/stl/inc/complex as an example, consider the class template and its specializations
template <class _Ty>
class complex;
template <>
class complex<float>;
template <>
class complex<double>;
template <>
class complex<long double>;
There are already definitions in the general class template. Take one definition for operator*= as an example,
template <class _Ty>
class complex : public _Complex_base<_Ty, _Complex_value<_Ty>> {
public:
// ...
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
this->_Val[_RE] = this->_Val[_RE] * _Right;
this->_Val[_IM] = this->_Val[_IM] * _Right;
return *this;
}
// ...
};
Why is this kind of code repeated again and again for almost all member functions in the specializations for float double and long double as below?
template <>
class complex<double> : public _Complex_base<double, _Dcomplex_value> {
public:
// ...
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
_Val[_RE] = _Val[_RE] * _Right;
_Val[_IM] = _Val[_IM] * _Right;
return *this;
}
// ...
};
What is the reason for such code duplication in the template specializations for std::complex<T>?
For reference, in the above MSVC code, it is
using _Dcomplex_value = _CSTD _C_double_complex;
For reference, the GNU implementation of <complex> can be found at https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/complex
For reference, the LLVM implementation of <complex> can be found at https://github.com/llvm/llvm-project/blob/main/libcxx/include/complex
For reference, the MSVC implementation of <complex> can be found at MSVC code at https://github.com/microsoft/STL/blob/main/stl/inc/complex

What is the reason for such code duplication
Short answer: return *this
You need to have each operator defined in the specializations in order to be able to return the correct type. Otherwise they would return references to the base class.
You could call the base class operator in the derived class, like
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
_Complex_base<_Ty, _Complex_value<_Ty>>::operator*=(_Right);
return *this;
}
but, even though is reduces repetition it really doesn't reduce the code size, or make it any more readable.

Related

Overloading Class Methods vs. Templates

I'm looking for an elegant way (defined by minimal repeated code) to overload an operator to do the following:
I have a template class BaseSignal which overloads the += operator, and I would like to be able to accept many different types. For example, for a double, the code looks like
template <class T>
class BaseSignal
{
public:
....
// Self-increment
BaseSignal<T>& operator+=(const double& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
....
What I've been doing is repeating this body of code for int, long, etc. Since the value rhs is only used in the line static_cast<T>(rhs), I am repeating code while only changing the input parameter type.
So I could template this, e.g.
template <class T, class U>
class BaseSignal
{
public:
....
// Self-increment
BaseSignal<T>& operator+=(const U& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
....
But then it looks like I lose the "overloading" aspect in that the compiler would automatically select the correct method for me (it would also only work for the original U type that was instantiated).
I realize that I am trying to achieve some untyped language behavior with C++, which may not be the smartest thing, I am just trying to add some intelligence to a few commonly-used classes so that subsequent code will become much easier to write.
Thank you in advance.
You might do
template <class T>
class BaseSignal
{
public:
// Self-increment
template <class U>
BaseSignal<T>& operator+=(const U& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
};

using enable_if to specialize on return type from a base class

I'm porting a large code base to clang (builds with g++ and intel c++). Code similar to the following snippet compiles and works on g++ 4.8 - 6.2 but fails to compile with clang 3.8 and 3.9. The second invocation of the MinOp should (AFAICT) get the base class specialization ("Don't call me!"), but clang attempts to instantiate the std::min version and fails:
#include <algorithm>
#include <iostream>
#include <type_traits>
template <typename T> class Vector
{
public:
Vector() : xyz{} {}
Vector(T const &x, T const &y, T const &z) : xyz{y, y, z} {}
Vector<T> min(Vector<T> const &v) { return Vector<T>(std::min(xyz[0], v.xyz[0]), std::min(xyz[1], v.xyz[1]), std::min(xyz[2], v.xyz[2])); }
T xyz[3];
};
class MinOpBase
{
public:
template <class T> typename std::enable_if<!std::is_fundamental<T>::value>::type
operator()(Vector<T> &left, Vector<T> const &right) const { std::cout << "Don't call me!" << std::endl; }
};
class MinOp : public MinOpBase
{
public:
template <typename T> void operator()(T &left, T const &right) const
{ left = std::min(left, right); }
// Support component-wise min on vectors of fundamental types
template <typename T> typename std::enable_if<std::is_fundamental<T>::value>::type
operator() (Vector<T> &left, Vector<T> const &right) const
{ left.min(right); }
using MinOpBase::operator();
};
int main()
{
Vector<double> v1, v2;
Vector<Vector<double>> vv1, vv2;
MinOp m;
m(v1,v2);
m(vv1,vv2);
}
Note that if there is no base class (MinOpBase), and the "Don't call me!" specialization is directly in the MinOp class, clang works too.
Is this use of a using statement to bring in the specialization from the base class valid?
This looks to me like a whole bunch of machinery for not very much value (although of course this has been simplified almost to the point of pointlessness). Better ideas?
A colleague pointed out that my question is a duplicate of
SFINAE not working on llvm/clang
I think the conclusion that clang is doing the "right" thing according to the standard is correct. From Johannes Schaub - litb's answer:
7.3.3 p15 of C++11 (the using declaration of the inherited function template is ignored because it has the same name and parameters as a
member function template of the derived class)
Although the other compilers are doing what probably ought to be the "right" thing. I don't know if this has been reported as a defect in the standard.
Work-arounds include putting all specializations into base classes or modifying one of the argument types of one of the specializations.

Only overload operator if template argument does

Given a template class A with a single template argument T, is it possible to only overload operators in A which are available for type T? For example:
template <typename T>
class A
{
public:
#if hasOperator(T, +=)
T& operator +=(const T &rhs)
{
mValue += rhs;
return mValue;
}
#endif
private:
T mValue;
}
int main()
{
A<int> a;
a += 8; //+= will forward to the += for the int
struct Test { /*no operators defined*/ };
A<Test> b; //+= is not implemented since Test does not implement +=
}
I'm writting a generic wrapper class that needs to behave exactly like the template type. So if T has operator +=, A will (at compile time) overload += accordingly. Yes, I could go ahead and just implement every operator in A, but then the compiler will error when T doesn't have a certain operator. At first I though template specialization might be the answer, but that would require a specialization for every type. While this could work and be a lot of typing, it wont because A needs to work with any type (not just what is specialized).
Use expression SFINAE to drop your operator+ from the overload resolution set unless T defines operator+
template <typename T>
class A
{
private:
T mValue;
public:
template<typename U=T>
auto operator +=(const U &rhs)
-> decltype(mValue += rhs)
{
mValue += rhs;
return mValue;
}
};
Live demo
I will give 3 solutions in decreasing complexity and utility. The last solution is the simplest, and least complex.
A small, if useful, metaprogramming library:
template<class...>struct types{using type=types;};
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z,types<Ts...>,std::void_t<Z<Ts...>>> :
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,types<Ts...>>;
A trait for the result of +=:
template<class Lhs, class Rhs>
using plus_equal_result = decltype(std::declval<Lhs>()+=std::declval<Rhs>());
template<class Lhs, class Rhs>
using can_plus_equal = can_apply< plus_equal_result, Lhs, Rhs >;
template<class T>
using can_self_plus_equal = can_plus_equal< T&, T const& >;
which gives us some nice traits that return true type or false type depending on if += is valid.
template<class A, class T, bool b = can_self_plus_equal<T>{}>
struct A_maybe_plus_equal {};
template<class A, class T>
struct A_maybe_plus_equal<A, T, true> {
A& self() { return *static_cast<A*>(this); }
A& operator+=( T && t )
{
self().mResult += std::move(t);
return self();
}
template<class U>
std::enable_if_t<can_plus_equal<T&,U>{},A&> operator+=( U && u )
{
self().mResult += std::forward<U>(u);
return self();
}
};
which gives us a += iff we pass true.
template <class T>
class A:
public A_maybe_plus_equal<A<T>, T>
{
friend class A_maybe_plus_equal<A<T>, T>;
public:
// nothing needed
private:
T mValue;
};
which gives you a += overload that takes a const T& or a T&& or a U&& on the right hand side if and only if T& += T const& is a valid expression.
This is the "perfect" solution, but it is complex.
Note that each operator can be done separately, so you don't have a combinatorial explosion of specializations.
Now, the there is an easier option. It has the downside that it doesn't support {} based construction on the right hand side, and under some readings of the standard it is illegal.
It is, however, still SFINAE friendly:
template <typename T>
class A {
public:
template<class U>
auto operator +=(U&&rhs)
-> decltype( (std::declval<T&>()+=std::declval<U&&>()),void(),A& )
// or std::enable_if_t<can_plus_equal<T&,U>{},A&>
{
mValue += std::forward<U>(rhs);
return *this;
}
private:
T mValue;
};
This can be folded into the above option, and give both {} and perfect forwarding syntax. I find that the T const& can be dropped if you have a template perfect forwarder.
The reason why this is technically undefined behavior is that the standard mandates that all template functions have at least one set of arguments that would render their body able to compile. In a given class instance, the template += of the above may have no such set of type arguments, which makes your program ill-formed with no diagnostic required (ie, UB).
There is another rule that member functions of template classes don't get instantiated unless called. Some argue that this other rule supersedes the one I mentioned in the last paragraph.
Another argument is that the method may be legal so long as there is some mixture of template arguments to the enclosing class(es) and to the template method itself that lead to it being instantiatable. I'd guess that this is what the standard committee intended, but I don't know how to read the standard to get this result.
This argument also applies to the plus_equal function in answer #1. That implementation need not be as simple. In addition, #1 provides {} based += syntax, which is a practical reason to use it. This concern -- that the program is technically ill-formed -- is academic, as all compilers I have used have no problems with this construct.
The paragraph three above this one gives us our final option. Do nothing.
template <typename T>
class A {
public:
A& operator +=(const T &rhs) {
mValue += rhs;
return *this;
}
private:
T mValue;
};
which means that you cannot SFINAE test that += doesn't work, but so long as you don't call += it "works". This is how vector's operator< works, for example. This is a lower "quality" solution, and cases of this in the standard library tend to be repaired over time.
However, as a first pass, this last choice is usually best. Only if you expect SFINAE requirements are the above hoops worthwhile.
Ultimately, C++1z is introducing concepts. I believe concepts will make this problem much easier, as eliminating overloads from consideration based on the type arguments of the enclosing class is a perennial problem in std.
You don't actually have to do anything. Individual member functions of a template class won't get instantiatiated until use. You say:
but then the compiler will error when T doesn't have a certain operator.
But isn't that clearer than having it error when A<T> doesn't? If you have:
template <typename T>
class A
{
public:
A& operator +=(const T &rhs)
{
mValue += rhs;
return *this;
}
A& operator-=(const T &rhs)
{
mValue -= rhs;
return *this;
}
// etc
private:
T mValue;
};
Then this will just work:
int main() {
A<int> a;
a += 8; //+= will forward to the += for the int
struct Test {
Test& operator-=(const Test& ) { return *this; }
};
A<Test> b;
b -= Test{}; // totally fine
b += Test{}; // error: no match for +=
// (operand types are 'main()::Test' and 'const main()::Test')
}

Is it ok to dynamic cast "this" as a return value?

This is more of a design question.
I have a template class, and I want to add extra methods to it depending on the template type. To practice the DRY principle, I have come up with this pattern (definitions intentionally omitted):
template <class T>
class BaseVector: public boost::array<T, 3>
{
protected:
BaseVector<T>(const T x, const T y, const T z);
public:
bool operator == (const Vector<T> &other) const;
Vector<T> operator + (const Vector<T> &other) const;
Vector<T> operator - (const Vector<T> &other) const;
Vector<T> &operator += (const Vector<T> &other)
{
(*this)[0] += other[0];
(*this)[1] += other[1];
(*this)[2] += other[2];
return *dynamic_cast<Vector<T> * const>(this);
}
virtual ~BaseVector<T>()
{
}
}
template <class T>
class Vector : public BaseVector<T>
{
public:
Vector<T>(const T x, const T y, const T z)
: BaseVector<T>(x, y, z)
{
}
};
template <>
class Vector<double> : public BaseVector<double>
{
public:
Vector<double>(const double x, const double y, const double z);
Vector<double>(const Vector<int> &other);
double norm() const;
};
I intend BaseVector to be nothing more than an implementation detail. This works, but I am concerned about operator+=. My question is: is the dynamic cast of the this pointer a code smell? Is there a better way to achieve what I am trying to do (avoid code duplication, and unnecessary casts in the user code)? Or am I safe since, the BaseVector constructor is private?
EDIT:
Sorry, yes I have virtual dtor, but I forgot to paste it, the code doesn't compile without it.
I would recommend that you consider an alternative approach (note that in the below examples, I have simplified the code to the bare minimum required to demonstrate the alternative approaches).
First, consider the Curiously Recurring Template Parameter (CRTP):
template <typename T, typename DerivedVector>
struct BaseVector
{
DerivedVector& operator+=(DerivedVector const& other)
{
return static_cast<DerivedVector&>(*this);
}
};
template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};
Since you always know what the derived type is, a static_cast is sufficient. If Vector<T> is the only class whose base is BaseVector<T> and if you are guaranteed that the T parameters are always the same, then strictly speaking, the CRTP parameter is unnecessary: you always know what the derived type is, so a static_cast is safe.
Alternatively, consider that operators need not be member functions, so you could declare non-member operator function templates:
template <typename T, typename DerivedVector>
struct BaseVector
{
};
template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};
template <typename T>
Vector<T>& operator+=(Vector<T>& self, Vector<T> const& other)
{
return self;
}
While the latter is preferable for operators, it won't work for ordinary, nonoperator member functions, so the CRTP approach would be preferable for those.
Yes, from a technical point of view it is OK. However, in order for the dynamic_cast to work your base class needs to be polymorphic. So you need to make at least the destructor (pure) virtual.
I also want to add that instead of:
// potential null dereference
return *dynamic_cast<Vector<T> * const>(this);
it is safer to write:
// potential std::bad_cast exception
return dynamic_cast<Vector<T> & const>(*this);
To answer your original question:
Is there a better way to achieve what I am trying to do (avoid code duplication, and unnecessary casts in the user code)?
Yes. Read about static polymorphism, curiously recurring template pattern and policy-based class design if you want to learn more.
None of your methods are virtual. Without any virtual methods, the compiler won't add any run-time type information. Without RTTI, dynamic_cast will not work.
I think a better way to accomplish this is the pimpl idiom. As you say, BaseVector is just an implementation detail. As such, clients of your class should have no knowledge of it (which leaves you free to change it).
In this case, this would entail having Vector contain a BaseVector rather than inherit from it. It would then define its own arithmetic assignment operators, which would forward to BaseVector.
This does not violate DRY, because there is still only one version of the implementation details, and they reside in BaseVector. Repeating the interface is perfectly fine.
This is an old question, but I recently had to solve this same problem and then happened to stumble across this, so I thought I'd answer.
I used a type wrapper in order to have the specialisation 'derive from itself':
template <class T>
struct type_wrapper;
template <class T>
struct unwrap_type
{
typedef T type;
};
template <class T>
struct unwrap_type<type_wrapper<T>>
{
typedef T type;
};
template <class WrappedT>
class Vector: public boost::array<typename unwrap_type<WrappedT>::type, 3>
{
typedef typename unwrap_type<WrappedT>::type T;
protected:
Vector(const T x, const T y, const T z);
public:
bool operator == (const Vector &other) const;
Vector<T> operator + (const Vector &other) const;
Vector<T> operator - (const Vector &other) const;
Vector<T> &operator += (const Vector &other)
{
(*this)[0] += other[0];
(*this)[1] += other[1];
(*this)[2] += other[2];
return static_cast<Vector<T> &>(*this);
}
}
template <>
class Vector<double> : public Vector<type_wrapper<double>>
{
public:
Vector(const double x, const double y, const double z);
Vector(const Vector<int> &other);
double norm() const;
};
That way, you don't need any redundant classes - except for the type wrapper and metafunction, which are reusable.

Overloading addition operator inside a template class

I'm trying to write some code for simple complex number manipulation. I'm using a template class and I'm having trouble overloading operators (specifically +,-,*,/). I'm trying to declare the overload inside my template class, and then define them after in the same header file.
My header code is as follows:
#ifndef MY_CLASS_H
#define MY_CLASS_H
template <class T> class complex
{
private:
T re,im;
public:
// Constructors & destructor
complex(){re=im=0;}
complex(T r, T i){re=r; im=i;}
~complex(){}
// Return real component
T realcomp() const {return re;}
// Return imaginary component
T imagcomp() const {return im;}
// Overload + operator for addition
complex<T> operator+(const complex<T> &C);
....
};
#endif
#include<iostream>
#include<cmath>
using namespace std;
template <class T> complex<T>& complex<T>::operator+(const complex &C){
complex<T> A(re+C.realcomp(),im+C.imagcomp());
return A;
}
This returns errors that I have so far been unable to solve and I'm not entirely sure where I've gone wrong. A mixture of me being a beginner to C++ and trying to puzzle together solutions to other issues on this website has probably meant that my code is a bit of a mess - I apologise!
Any help would be greatly appreciated.
The declaration for complex<T>::operator+ is returning a complex<T> while the definition is returning a complex<T>&. You want to return the object by value, not reference.
Also, template classes must have their function definitions in the header file, since the compiler needs to be able to see these when instantiating the templates, so move the operator+ definition to the header file.
You should also use constructor initialization lists to initialize the member variables.
template <class T> class complex
{
private:
T re,im;
public:
// Constructors & destructor
complex() : re(), im() {}
complex( const T& r, const T& i ) : re(r), im(i) {}
~complex(){}
// Return real component
T realcomp() const {return re;}
// Return imaginary component
T imagcomp() const {return im;}
// Overload + operator for addition
complex<T> operator+(const complex<T> &C)
{
return complex<T>( re + C.realcomp(), im + C.imagcomp() );
}
};
You mismatched the declaration with the definition. Change this line:
template <class T> complex<T>& complex<T>::operator+(const complex &C){
to this
template <class T> complex<T> complex<T>::operator+(const complex &C){
(Note the missing "&")
This should work:
template <class T> complex<T> complex<T>::operator+(const complex<T> &C){
complex<T> A(re+C.realcomp(),im+C.imagcomp());
return A;
}
The return value is declared to be an object in the class and the patameter is missing the template parameter
you are returning a local variable as reference. plus the declaration are different:
you declare to return a complex while on definition you return a complex&