Consider the following class:
template <typename Type>
class Wrapper
{
public:
Wrapper(const Type& x) : _data(x) {;}
Wrapper<Type>& operator=(const Type& x) {_data = x; return *this;}
protected:
Type _data;
};
What would be the definition of the move constructor Wrapper(Type&& x) and the move assignment operator operator=(Type&& x) of this class ?
Wrapper(Type&& x) : _data(std::move(x)) {}
Wrapper& operator=(Type&& x) {_data = std::move(x); return *this;}
An interesting way to write this in C++11 is:
template<typename A, typename B, typename T=void*>
using IfSameBaseType = std::enable_if<
typename std::is_same<
typename std::remove_cv<A>::type,
typename std::remove_cv<B>::type
>::type,
T
>::type;
template <typename T>
class Wrapper
{
public:
template<typename U, typename unused>
Wrapper(U&& u, unused* do_not_use=(IfSameBaseType<T,U>*)nullptr) :
data_( std::forward(u) )
{}
template<typename U>
IfSameBaseType<T,U,Wrapper<Type>>& operator=(U&& x) {
data_ = std::forward(x);
return *this;
}
protected:
T data_;
};
here, I use && in a type deduction context to provide a single override for l and r value references, which I then pass on via std::forward. The IsSameBaseType stuff just makes sure that I only write constructors for the type T -- I could extend this and say "is implicitly convertible to T" instead of IsSameBaseType without all that much hassle.
The advantage of this is that we have fewer duplicate methods. The disadvantage is all that template tomfoolery could distract someone from the point of it all.
Related
I have a class that wraps some type and attaches a Dimension. It should be convertible to the underlying type, but only if Dim=0. The conversion operator should not be callable in other cases (so a static_assert in the function would not work for me).
The following code works, if the enable_if-construction is deleted, but not in this form.
template<class T, int Dim>
class Unit {
public:
explicit Unit(T const& value): _value(value) {}
template<int D = Dim, typename = typename std::enable_if<D == 0>::type>
operator T() { return _value; }
private:
T _value;
};
auto main() -> int
{
auto a = double{0};
auto u = Unit<double, 0>{a};
auto i = static_cast<int>(u);
return i;
}
What is the reason for this and is there a work around to allow the cast, but also restrict the conversion?
As I understand, you want:
template <class T, int Dim>
class Unit {
public:
explicit Unit(T const& value): _value(value) {}
template <typename U, int D = Dim,
std::enable_if_t<D == 0 && std::is_convertible_v<T, U>, int> = 0>
operator U() { return _value; }
private:
T _value;
};
Demo
And in C++20, look nicer
template<class T, int Dim>
class Unit {
public:
explicit Unit(T const& value): _value(value) {}
template <typename U>
requires(Dim == 0 && std::is_convertible_v<T, U>)
operator U() const { return _value; }
private:
T _value;
};
Demo
I have a class template with a conversion constructor to the template type. And a function that takes two parameters of that class template. I referred to this question/answer to allow the function to make use of the conversion constructor, however the answer states that you can only call the function if at least one of the arguments is explicitly constructed. Is there any other way to allow the function to be called with all the arguments implicitly constructed?
so this is what I have after referring to the mentioned link. This works if at least argument lhs or rhs are explicitly of type X, and I want it to work even if both are of type T.
template<typename T>
class X {
public:
X(T t) {}
friend void func(X lhs, X rhs) {}
};
If I correctly understand your problem, you may add overload:
template<typename T>
class X {
public:
X(T t) {}
friend void func(const X& lhs, const X& rhs) {}
};
template <typename T> X<T> asX(const T& t) { return {t}; }
template <typename T> const X<T>& asX(const X<T>& x) { return x; }
template<typename LHS, typename RHS>
void func(const LHS& lhs, const RHS& rhs) { return func(asX(lhs), asX(rhs)); }
Demo
With n different classes, which should all be comparable with operator== and operator!=, it would be necessary to implement (n ^ 2 - n) * 2 operators manually. (At least I think that's the term)
That would be 12 for three classes, 24 for four. I know that I can implement a lot of them in terms of other operators like so:
operator==(A,B); //implemented elsewhere
operator==(B,A){ return A == B; }
operator!=(A,B){ return !(A == B); }
but it still seems very tedious, especially because A == B will always yield the same result as B == A and there seems to be no reason whatsoever to implement two version of them.
Is there a way around this? Do I really have to implement A == B and B == A manually?
Use Boost.Operators, then you only need to implement one, and boost will define the rest of the boilerplate for you.
struct A
{};
struct B : private boost::equality_comparable<B, A>
{
};
bool operator==(B const&, A const&) {return true;}
This allows instances of A and B to be compared for equality/inequality in any order.
Live demo
Note: private inheritance works here because of the Barton–Nackman trick.
In the comments the problem is further explained by stating that all of the types are really different forms of smart pointers with some underlying type. Now this simplifies quite a lot the problem.
You can implement a generic template for the operation:
template <typename T, typename U>
bool operator==(T const & lhs, U const & rhs) {
return std::addressof(*lhs) == std::addressof(*rhs);
}
Now this is a bad catch all (or rather catch too many) implementation. But you can narrow down the scope of the operator by providing a trait is_smart_ptr that detects whether Ptr1 and Ptr2 are one of your smart pointers, and then use SFINAE to filter out:
template <typename T, typename U,
typename _ = typename std::enable_if<is_pointer_type<T>::value
&& is_pointer_type<U>::value>::type >
bool operator==(T const & lhs, U const & rhs) {
return std::addressof(*lhs) == std::addressof(*rhs);
}
The type trait itself can be just a list of specializations of a template:
template <typename T>
struct is_pointer_type : std::false_type {};
template <typename T>
struct is_pointer_type<T*> : std::true_type {};
template <typename T>
struct is_pointer_type<MySmartPointer<T>> : std::true_type {};
template <typename T>
struct is_pointer_type<AnotherPointer<T>> : std::true_type {};
It probably makes sense not to list all of the types that match the concept of pointer, but rather test for the concept, like:
template <typename T, typename U,
typename _ = decltype(*declval<T>())>
bool operator==(T const & lhs, U const & rhs) {
return std::addressof(*lhs) == std::addressof(*rhs);
}
Where the concept being tested is that it has operator* exists. You could extend the SFINAE check to verify that the stored pointer types are comparable (i.e. that std::addressof(*lhs) and std::addressof(*rhs) has a valid equality:
template <typename T, typename U,
typename _ = decltype(*declval<T>())>
auto operator==(T const & lhs, U const & rhs)
-> decltype(std::addressof(*lhs) == std::addressof(*rhs))
{
return std::addressof(*lhs) == std::addressof(*rhs);
}
And this is probably as far as you can really get: You can compare anything that looks like a pointer to two possibly unrelated objects, if raw pointers to those types are comparable. You might need to single out the case where both arguments are raw pointers to avoid this entering out into a recursive requirement...
not necesarily:
template<class A, class B>
bool operator==(const A& a, const B& b)
{ return b==a; }
works for whatever A and B there is a B==A implementation (otherwise will recourse infinitely)
You can also use CRTP if you don't want the templetized == to work for everything:
template<class Derived>
class comparable {};
class A: public comparable<A>
{ ... };
class B: public comparable<B>
{ ... };
bool operator==(const A& a, const B& b)
{ /* direct */ }
// this define all reverses
template<class T, class U>
bool operator==(const comparable<T>& sa, const comparable<U>& sb)
{ return static_cast<const U&>(sb) == static_cast<const T&>(sa); }
//this defines inequality
template<class T, class U>
bool operator!=(const comparable<T>& sa, const comparable<U>& sb)
{ return !(static_cast<const T&>(sa) == static_cast<const U&>(sb)); }
Using return type SFINAE yo ucan even do something like
template<class A, class B>
auto operator==(const A& a, const B& b) -> decltype(b==a)
{ return b==a; }
template<class A, class B>
auto operator!=(const A& a, const B& b) -> decltype(!(a==b))
{ return !(a==b); }
The goal here is to deal with large n reasonably efficiently.
We create an order, and forward all comparison operators to comp after reordering them to obey that order.
To do this, I start with some metaprogramming boilerplate:
template<class...>struct types{using type=types;};
template<class T,class types>struct index_of{};
template<class T,class...Ts>struct index_of<T,types<T,Ts...>>:
std::integral_constant<unsigned,0>
{};
template<class T,class U,class...Us>struct index_of<T,types<U,Us...>>:
std::integral_constant<unsigned,1+index_of<T,types<Us...>>::value>
{};
which lets us talk about ordered lists of types. Next we use this to impose an order on these types:
template<class T, class U,class types>
struct before:
std::integral_constant<bool, (index_of<T,types>::value<index_of<U,types>::value)>
{};
Now we make some toy types and a list:
struct A{}; struct B{}; struct C{};
typedef types<A,B,C> supp;
int comp(A,B);
int comp(A,C);
int comp(B,C);
int comp(A,A);
int comp(B,B);
int comp(C,C);
template<class T,class U>
std::enable_if_t<before<T,U,supp>::value, bool>
operator==(T const& t, U const& u) {
return comp(t,u)==0;
}
template<class T,class U>
std::enable_if_t<!before<T,U, supp>::value, bool>
operator==(T const& t, U const& u) {
return comp(u,t)==0;
}
template<class T,class U>
std::enable_if_t<before<T,U,supp>::value, bool>
operator<(T const& t, U const& u) {
return comp(t,u)<0;
}
template<class T,class U>
std::enable_if_t<!before<T,U, supp>::value, bool>
operator<(T const& t, U const& u) {
return comp(u,t)>0;
}
etc.
The basic idea is that supp lists the types you want to support, and their prefered order.
Boilerplate operators then forward everything to comp.
You need to implement n*(n-1)/2 comps to handles each pair, but only in one order.
Now for the bad news: probably you want to lift each type to some common type and compare there, rather than het lost in the combinatorial morass.
Suppose you can define a type Q which can store the imformation required to sort any of them.
Then write convert-to-Q code from each type, and implement comparison on Q. This reduces the code written to O(a+b), where a is the number of types and b the number of operators supported.
As an example, smart pointers can be pointer-ordered between each other this way.
In an attempt to write a wrapper type for another type T, I encountered a rather obnoxious problem: I would like to define some binary operators (such as +) that forward any operation on wrapper to the underlying type, but I need these operators accept any of the potential combinations that involve wrapper:
wrapper() + wrapper()
wrapper() + T()
T() + wrapper()
The naive approach involves writing all the potential overloads directly.
But I don't like writing duplicated code and wanted a bit more challenge, so I chose to implement it using a very generic template and restrict the potential types with an enable_if.
My attempt is shown at the bottom of the question (sorry, this is as minimal as I can think of). The problem is that it will run into an infinite recursion error:
To evaluate test() + test(), the compile looks at all potential overloads.
The operator defined here is in fact a potential overload, so it tries to construct the return type.
The return type has an enable_if clause, which is supposed to prevent it from being a valid overload, but the compiler just ignores that and tries to compute the decltype first, which requires ...
... an instantiation of operator+(test, test).
And we're back where we started. GCC is nice enough to spit an error; Clang just segfaults.
What would be a good, clean solution for this? (Keep in mind that there are also other operators that need to follow the same pattern.)
template<class T>
struct wrapper { T t; };
// Checks if the type is instantiated from the wrapper
template<class> struct is_wrapper : false_type {};
template<class T> struct is_wrapper<wrapper<T> > : true_type {};
// Returns the underlying object
template<class T> const T& base(const T& t) { return t; }
template<class T> const T& base(const wrapper<T>& w) { return w.t; }
// Operator
template<class W, class X>
typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value,
decltype(base(declval<W>()) + base(declval<X>()))
>::type operator+(const W& i, const X& j);
// Test case
struct test {};
int main() {
test() + test();
return 0;
}
Here's rather clunky solution that I would rather not use unless I have to:
// Force the evaluation to occur as a 2-step process
template<class W, class X, class = void>
struct plus_ret;
template<class W, class X>
struct plus_ret<W, X, typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value>::type> {
typedef decltype(base(declval<W>()) + base(declval<X>())) type;
};
// Operator
template<class W, class X>
typename plus_ret<W, X>::type operator+(const W& i, const X& j);
As an addition to the comment of TemplateRex, I would suggest use a macro to implement all overloads and take the operator as an argument:
template<class T>
struct wrapper { T t; };
#define BINARY_OPERATOR(op) \
template<class T> \
T operator op (wrapper<T> const& lhs, wrapper<T> const& rhs); \
template<class T> \
T operator op (wrapper<T> const& lhs, T const& rhs); \
template<class T> \
T operator op (T const& lhs, wrapper<T> const& rhs);
BINARY_OPERATOR(+)
BINARY_OPERATOR(-)
#undef BINARY_OPERATOR
// Test case
struct test {};
test operator+(test const&, test const&);
test operator-(test const&, test const&);
int main() {
test() + test();
wrapper<test>() + test();
test() - wrapper<test>();
return 0;
}
This is something that is touched upon on the boost page for enable_if, in an unerringly similar situation (though the error they wish to avoid is different). The solution of boost was to create a lazy_enable_if class.
The problem, as it is, is that the compiler will attempt to instantiate all the types present in the function signature, and thus the decltype(...) expression too. There is also no guarantee that the condition is computed before the type.
Unfortunately I could not come up with a solution to this issue; my latest attempt can be seen here and still triggers the maximum instantiation depth issue.
The most straightforward way to write mixed-mode arithmetic is to follow Scott Meyers's Item 24 in Effective C++
template<class T>
class wrapper1
{
public:
wrapper1(T const& t): t_(t) {} // yes, no explicit here
friend wrapper1 operator+(wrapper1 const& lhs, wrapper1 const& rhs)
{
return wrapper1{ lhs.t_ + rhs.t_ };
}
std::ostream& print(std::ostream& os) const
{
return os << t_;
}
private:
T t_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, wrapper1<T> const& rhs)
{
return rhs.print(os);
}
Note that you would still need to write operator+= in order to provide a consistent interface ("do as the ints do"). If you also want to avoid that boilerplate, take a look at Boost.Operators
template<class T>
class wrapper2
:
boost::addable< wrapper2<T> >
{
public:
wrapper2(T const& t): t_(t) {}
// operator+ provided by boost::addable
wrapper2& operator+=(wrapper2 const& rhs)
{
t_ += rhs.t_;
return *this;
}
std::ostream& print(std::ostream& os) const
{
return os << t_;
}
private:
T t_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, wrapper2<T> const& rhs)
{
return rhs.print(os);
}
In either case, you can then write
int main()
{
wrapper1<int> v{1};
wrapper1<int> w{2};
std::cout << (v + w) << "\n";
std::cout << (1 + w) << "\n";
std::cout << (v + 2) << "\n";
wrapper2<int> x{1};
wrapper2<int> y{2};
std::cout << (x + y) << "\n";
std::cout << (1 + y) << "\n";
std::cout << (x + 2) << "\n";
}
which will print 3 in all cases. Live example. The Boost approach is very general, e.g. you can derive from boost::arithmetic to also provide operator* from your definition of operator*=.
NOTE: this code relies on implicit conversions of T to wrapper<T>. But to quote Scott Meyers:
Classes supporting implicit type conversions are generally a bad idea.
Of course, there are exceptions to this rule, and one of the most
common is when creating numerical types.
I have a better answer for your purpose: don't make it to complicated, don't use to much meta programming. Instead use simple function to unwrap and use normal expressions. You don't need to use enable_if to remove to operators from function overload set. If they are not used the will never need to compile and if the are used they give a meaningfull error.
namespace w {
template<class T>
struct wrapper { T t; };
template<class T>
T const& unwrap(T const& t) {
return t;
}
template<class T>
T const& unwrap(wrapper<T> const& w) {
return w.t;
}
template<class T1,class T2>
auto operator +(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)+unwrap(t2)) {
return unwrap(t1)+unwrap(t2);
}
template<class T1,class T2>
auto operator -(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)-unwrap(t2)) {
return unwrap(t1)-unwrap(t2);
}
template<class T1,class T2>
auto operator *(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)*unwrap(t2)) {
return unwrap(t1)*unwrap(t2);
}
}
// Test case
struct test {};
test operator+(test const&, test const&);
test operator-(test const&, test const&);
int main() {
test() + test();
w::wrapper<test>() + w::wrapper<test>();
w::wrapper<test>() + test();
test() - w::wrapper<test>();
return 0;
}
Edit:
As an intersting additional information I have to say, the orignal soultion from fzlogic compiles under msvc 11 (but not 10). Now my solution (presented here) doesn't compile on both (gives C1045). If you need to address these isues with msvc and gcc (I don't have clang here) you have to move logic to different namespaces and functions to prevent the compiler to uses ADL and take the templated operator+ into consideration.
template<typename T>
struct A
{
A<T> operator%( const T& x);
};
template<typename T>
A<T> A<T>::operator%( const T& x ) { ... }
How can I use enable_if to make the following specialization happen for any floating point type (is_floating_point)?
template<>
A<float> A<float>::operator%( const float& x ) { ... }
EDIT:
Here's an answer I came up which is different from the ones posted below...
template<typename T>
struct A
{
T x;
A( const T& _x ) : x(_x) {}
template<typename Q>
typename std::enable_if<std::is_same<Q, T>::value && std::is_floating_point<Q>::value, A<T> >::type operator% ( const Q& right ) const
{
return A<T>(fmod(x, right));
}
template<typename Q>
typename std::enable_if<std::is_convertible<Q, T>::value && !std::is_floating_point<Q>::value, A<T> >::type operator% ( const Q& right ) const
{
return A<T>(x%right);
}
};
Like the below posters say, using enable_if may not be ideal for this problem (it's very difficult to read)
Use overloading instead of explicit specialization when you want to refine the behavior for a more specific parameter type. It's easier to use (less surprises) and more powerful
template<typename T>
struct A
{
A<T> operator%( const T& x) {
return opModIml(x, std::is_floating_point<T>());
}
A<T> opModImpl(T const& x, std::false_type) { /* ... */ }
A<T> opModImpl(T const& x, std::true_type) { /* ... */ }
};
An example that uses SFINAE (enable_if) as you seem to be curious
template<typename T>
struct A
{
A<T> operator%( const T& x) {
return opModIml(x);
}
template<typename U,
typename = typename
std::enable_if<!std::is_floating_point<U>::value>::type>
A<T> opModImpl(U const& x) { /* ... */ }
template<typename U,
typename = typename
std::enable_if<std::is_floating_point<U>::value>::type>
A<T> opModImpl(U const& x) { /* ... */ }
};
Way more ugly of course. There's no reason to use enable_if here, I think. It's overkill.
You can also use a default boolean template parameter like this:
template<typename T>
struct A
{
T x;
A( const T& _x ) : x(_x) {}
template<bool EnableBool = true>
typename std::enable_if<std::is_floating_point<T>::value && EnableBool, A<T> >::type
operator% ( const T& right ) const
{
return A<T>(fmod(x, right));
}
template<bool EnableBool = true>
typename std::enable_if<!std::is_floating_point<T>::value && EnableBool, A<T> >::type
operator% ( const T& right ) const
{
return A<T>(x%right);
}
};
With C++20
You can achieve that simply by adding requires to restrict the relevant template function:
template<typename Q> // the generic case, no restriction
A<T> operator% ( const Q& right ) const {
return A<T>(std::fmod(x, right));
}
template<typename Q> requires std::is_integral_v<T> && std::is_integral_v<Q>
A<T> operator% ( const Q& right ) const {
return A<T>(x % right);
}
The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this method in the overload resolution, if the requires clause is true the method is preferred over another one that has no requires clause, as it is more specialized.
Code: https://godbolt.org/z/SkuvR9