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
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
For instance, let's say I have a simple 2D vector templated structure:
template <typename T>
struct Vec { T x, y; };
And a generic way to do summation:
template <typename T, typename U>
constexpr auto operator+(const Vec<T>& u, const Vec<U>& v) {
return Vec<decltype(u.x + v.x)>{u.x + v.x, u.y + v.y};
}
But I have to rewrite template <typename T, typename U> for all the other basic operations (-, *, / etc.). I wish I could do something like:
template <typename T, typename U>
{
constexpr auto operator+(const Vec<T>& u, const Vec<U>& v) { /* ... */ };
constexpr auto operator-(const Vec<T>& u, const Vec<U>& v) { /* ... */ };
/* ... */
}
Also, as said in this thread, auto is not permitted when nested within a decl-specifier, which means that the below solution isn't valid (even if it compiles somehow):
constexpr auto operator+(const Vec<auto>& u, const Vec<auto>& v) { /* ... */ }
You can save one template parameter, by defining the operators inline:
template <typename T>
struct Vec {
T x, y;
template<class U> auto operator+(Vec<U> const& v)
{ return Vec<decltype(x + v.x)>{x + v.x, y + v.y};}
template<class U> auto operator-(Vec<U> const& v)
{ return Vec<decltype(x - v.x)>{x - v.x, y - v.y};}
};
If you completely want to avoid writing repetitive code, macros would be a way to avoid that (whether that is good practice, and whether it helps or disturbs understanding the code, is probably a question of taste and context)
Here is the code:
template <typename L, typename R> bool eq (const L& lhs, const R& rhs) { return lhs == rhs; }
template<int N> bool eq(char* lhs, const char(&rhs)[N]) { return String(lhs).compare(rhs) == 0; }
template<int N> bool eq(const char(&lhs)[N], char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(char* lhs, char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(const char* lhs, char* rhs) { return String(lhs).compare(rhs) == 0; }
I have to do this for neq/lt/gt/lte/gte and not just for equality. Maybe I've already missed something.
Is there a way to not list all the possible combinations of C string types?
Also C++98.
EDIT: >> here << is an online demo with the problem
Decay an array type to pointer:
template<class T>
struct decay_array { typedef T type; };
template<class T, size_t N>
struct decay_array<T[N]> { typedef T* type; };
template<class T>
struct decay_array<T[]> { typedef T* type; };
Check that a type is not a pointer to (possibly const) char:
template<class T>
struct not_char_pointer { enum { value = true }; };
template<>
struct not_char_pointer<char*> { enum { value = false }; };
template<>
struct not_char_pointer<const char*> { enum { value = false }; };
Now check that a type is not a pointer to or array of (possibly const) char:
template<class T>
struct can_use_op : not_char_pointer<typename decay_array<T>::type> {};
Reimplement std::enable_if:
template<bool, class = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
and use it to constrain your template:
template <typename L, typename R>
typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
eq (const L& lhs, const R& rhs) { return lhs == rhs; }
Then just one overload is enough:
inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
namespace details{
template<template<class...>class Z,class,class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z,class...Ts>
struct can_apply<Z,std::void_t<Z<Ts...>>,Ts...>:std::true_type{};
}
template<template<class...>class Z,class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
This tests if a template can be applied some types.
namespace strcmp{
bool eq(const char*lhs, const char*rhs){/* body */}
}
template<class L, class R>
using str_eq_r=decltype(strcmp::eq(std::declval<L>(),std::declval<R>()));
template<class L, class R>
using can_str_eq=can_apply<str_eq_r,L,R>;
can_str_eq is truthy iff we can call stdcmp::eq on it.
namespace details {
bool eq(const char* lhs, const char* rhs, std::true_type){
return strcmp::eq(lhs,rhs);
}
template<class L,class R>
bool eq(L const& l, R const&r,std::false_type){
return l==r;
}
}
template<class L,class R>
bool eq(L const& l, R const&r){
return details::eq(l,r,can_str_eq<L const&,R const&>{});;
}
We could also use a static_if trick to do it inline, if you like:
template<class L,class R>
bool eq(L const& l, R const&r){
return static_if<can_str_eq>( l, r )(
strcmp::eq,
[](auto&& l, auto&& r){return l==r;}
);
}
After writing a static_if:
template<class...Ts>
auto functor(Ts...ts){
return [=](auto&& f){
return f(ts...);
};
}
namespace details{
template<class Functor>
auto switcher(std::true_type, Functor functor){
return [=](auto&& t, auto&&){
return functor(t);
};
}
template<class Functor>
auto switcher(std::false_type, Functor functor){
return [=](auto&&, auto&& f){
return functor(f);
};
}
}
template<template<class...>class test, class...Ts>
auto static_if(Ts...ts){
return details::switcher(
test<Ts...>{},
functor(ts...)
);
}
now, what are the odds that works? (Written on phone, not compiled yet) Also not optimal: lots of perfect forwarding, some of which requires de-lamdaing, required.
Supose I need to write a class which acts as a wrapper for values:
template<typename T>
struct value_wrapper
{
T value;
value_wrapper( const T& v ) : value( v ) {}
//etc...
};
The class is dessigned to be used as an alias of the original value, so if that value was an rvalue, the wrapper holds the value, and if it was an lvalue the wrapper holds a reference to it.
The class is supposed to overload, say, comparison operators and be used in this way:
template<typename T , typename U>
bool f( const T& lhs , const T& rhs )
{
return wrapper( lhs ) == wrapper( rhs );
}
Or this:
int main()
{
int a , b;
bool flag = wrapper( a ) == wrapper( b ) || wrapper( a ) == wrapper( 2 );
}
My question is: Whats the best (efficient) way to implement such thing?
That questions seems to broad, I mean:
How I define the member value? As T& for lvalues, and T for rvalues?
Is there any standard way to write this kind of universal (rvalue and lvalue) alias?
I would simply provide suitable conversion operators:
#include <utility>
#include <type_traits>
template <typename T> struct Wrapper
{
static_assert(!std::is_reference<T>::value, "Do not use a reference type");
using type = T;
T value;
Wrapper(T && t) : value(std::move(t)) {}
Wrapper(T const & t) : value(t) {}
operator T const & () const noexcept { return value; }
operator T & () & noexcept { return value; }
operator T && () && noexcept { return std::move(value); }
// maybe some more CV variants...
};
template <typename U> struct Wrapper<U &>
{
using type = U &;
U & ref;
Wrapper(U & u) : ref(u) {}
operator U & () { return ref; }
};
I'd accompany this with a deducing function:
template <typename T> Wrapper<T> wrap(T && t)
{ return Wrapper<T>(std::forward<T>(t)); }
Example usage:
int n = 10;
bool b = wrap(n) == wrap(5 + 5)
The conversion operators allow you to use whatever operators are defined on the underlying type.
I think Kerrek SB is on the right track by providing a specialization (got my +1 a long time ago), so each case is handled most efficiently.
The problem is you can't just add implicit conversion operators and if you want to provide your own operator overloads, things can become quite tricky.
The solution I came up with tries to deal with this by putting the information which case a certain variable is into a boolean template parameter. Here's the basic framework for the value_wrapper class:
template< typename T, bool >
class value_wrapper
{
private:
T t_; // store a value
public:
explicit value_wrapper( T&& t ) : t_( std::move( t ) ) {}
const T& cref() const { return t_; }
};
template< typename T >
struct value_wrapper< T, true > // specialization for lvalue references
{
private:
const T& t_; // store a reference
public:
explicit value_wrapper( const T& t ) : t_( t ) {}
const T& cref() const { return t_; }
};
The tricky part is the convenience method to wrap the values:
// needs a better name and needs to be moved into a "detail" or "impl" namespace
template< typename T >
using helper = value_wrapper< typename std::decay< T >::type,
std::is_lvalue_reference< T >::value >;
template< typename T >
helper< T > wrap( T&& t )
{
return helper< T >( std::forward< T >( t ) );
}
That way value_wrapper's first template parameter is always the decayed type, which makes everything easier now:
template< typename T, bool BL, bool BR >
bool operator==( const value_wrapper< T, BL >& lhs, const value_wrapper< T, BR >& rhs )
{
return lhs.cref() == rhs.cref();
}
(obviously you want to implement them differently, but you can always access the stored values via cref() in a uniform way)
Live example
You might need to adjust this if you need non-constant access, etc. but I hope the above gets you started. If you need more help/ideas, feel free to ask :)
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.