I am trying to create an example, which would check the existence of the operator== (member or, non-member function). To check whether a class has a member operator== is easy, but how to check whether it has a non-member operator==?
This is what I have to far :
#include <iostream>
struct A
{
int a;
#if 0
bool operator==( const A& rhs ) const
{
return ( a==rhs.a);
}
#endif
};
#if 1
bool operator==( const A &l,const A &r )
{
return ( l.a==r.a);
}
#endif
template < typename T >
struct opEqualExists
{
struct yes{ char a[1]; };
struct no { char a[2]; };
template <typename C> static yes test( typeof(&C::operator==) );
//template <typename C> static yes test( ???? );
template <typename C> static no test(...);
enum { value = (sizeof(test<T>(0)) == sizeof(yes)) };
};
int main()
{
std::cout<<(int)opEqualExists<A>::value<<std::endl;
}
Is it possible to write a test function to test the existence of non-member operator==?
If yes, how?
btw I have checked similar questions, but haven't found a proper solution :
Is it possible to use SFINAE/templates to check if an operator exists?
This is what I tried :
template <typename C> static yes test( const C*,bool(*)(const C&,constC&) = &operator== );
but the compilation fails if the non-member operator== is removed
C++03
The following trick works and it can be used for all such operators:
namespace CHECK
{
class No { bool b[2]; };
template<typename T, typename Arg> No operator== (const T&, const Arg&);
bool Check (...);
No& Check (const No&);
template <typename T, typename Arg = T>
struct EqualExists
{
enum { value = (sizeof(Check(*(T*)(0) == *(Arg*)(0))) != sizeof(No)) };
};
}
Usage:
CHECK::EqualExists<A>::value;
The 2nd template typename Arg is useful for some special cases like A::operator==(short), where it's not similar to class itself. In such cases the usage is:
CHECK::EqualExists<A, short>::value
// ^^^^^ argument of `operator==`
Demo.
C++11
We need not use sizeof and null reference trick when we have decltype and std::declval
namespace CHECK
{
struct No {};
template<typename T, typename Arg> No operator== (const T&, const Arg&);
template<typename T, typename Arg = T>
struct EqualExists
{
enum { value = !std::is_same<decltype(std::declval<T>() < std::declval<Arg>()), No>::value };
};
}
Demo
Have a look at Boost's Concept Check Library (BCCL) http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm.
It enables you to write requirements that a class must match in order for the program to compile. You're relatively free with what you can check. For example, verifying the presence of operator== of a class Foo would write as follow:
#include <boost/concept_check.hpp>
template <class T>
struct opEqualExists;
class Foo {
public:
bool operator==(const Foo& f) {
return true;
}
bool operator!=(const Foo& f) {
return !(*this == f);
}
// friend bool operator==(const Foo&, const Foo&);
// friend bool operator!=(const Foo&, const Foo&);
};
template <class T>
struct opEqualExists {
T a;
T b;
// concept requirements
BOOST_CONCEPT_USAGE(opEqualExists) {
a == b;
}
};
/*
bool operator==(const Foo& a, const Foo& b) {
return true; // or whatever
}
*/
/*
bool operator!=(const Foo& a, const Foo& b) {
return ! (a == b); // or whatever
}
*/
int main() {
// no need to declare foo for interface to be checked
// declare that class Foo models the opEqualExists concept
// BOOST_CONCEPT_ASSERT((opEqualExists<Foo>));
BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Foo>)); // need operator!= too
}
This code compiles fine as long as one of the two implementations of operator== is available.
Following #Matthieu M. and #Luc Touraille advice, I updated the code snippet to provide an example of boost::EqualityComparable usage. Once again, please note that EqualityComparable forces you to declare operator!= too.
It's also possible to use only c++11 type traits to check the existence of the member:
#include <type_traits>
#include <utility>
template<class T, class EqualTo>
struct has_operator_equal_impl
{
template<class U, class V>
static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>());
template<typename, typename>
static auto test(...) -> std::false_type;
using type = typename std::is_same<bool, decltype(test<T, EqualTo>(0))>::type;
};
template<class T, class EqualTo = T>
struct has_operator_equal : has_operator_equal_impl<T, EqualTo>::type {};
You can use the trait like so:
bool test = has_operator_equal<MyClass>::value;
The resulting type of has_operator_equal will either be std::true_type or std::false_type (because it inherits from an alias of std::is_same::type), and both define a static value member which is a boolean.
If you want to be able to test whether your class defines operator==(someOtherType), you can set the second template argument:
bool test = has_operator_equal<MyClass, long>::value;
where the template parameter MyClass is still the class that you are testing for the presence of operator==, and long is the type you want to be able to compare to, e.g. to test that MyClass has operator==(long).
if EqualTo (like it was in the first example) is left unspecified, it will default to T, result in the normal definition of operator==(MyClass).
Note of caution: This trait in the case of operator==(long) will be true for long, or any value implicitly convertible to long, e.g. double, int, etc.
You can also define checks for other operators and functions, just by replacing what's inside the decltype. To check for !=, simply replace
static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>());
with
static auto test(U*) -> decltype(std::declval<U>() != std::declval<V>());
C++20
I guess you want to check whether a user-provided type has equality operator or not; if that is the case then Concepts are here to help.
#include <concepts>
struct S{
int x;
};
template<std::equality_comparable T>
bool do_magic(T a, T b)
{
return a == b;
}
int main()
{
// do_magic(S{}, S{}); Compile time error
do_magic(56, 46); // Okay: int has == and !=
}
If you pass any type that does not have == and != defined, the compiler just errors out with message, e.g.:
equality_comparable concept not satisfied by type
You can also use std::equality_comparable_with<T, U> concept to check for those overload between two different types.
There are many more concepts that have been added to standards such as std::incrementable etc.. Have a look at Standard Library concepts as a good starting point.
As of c++14, the standard binary functions do most of the work for us for the majority of operators.
#include <utility>
#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>
template<class X, class Y, class Op>
struct op_valid_impl
{
template<class U, class L, class R>
static auto test(int) -> decltype(std::declval<U>()(std::declval<L>(), std::declval<R>()),
void(), std::true_type());
template<class U, class L, class R>
static auto test(...) -> std::false_type;
using type = decltype(test<Op, X, Y>(0));
};
template<class X, class Y, class Op> using op_valid = typename op_valid_impl<X, Y, Op>::type;
namespace notstd {
struct left_shift {
template <class L, class R>
constexpr auto operator()(L&& l, R&& r) const
noexcept(noexcept(std::forward<L>(l) << std::forward<R>(r)))
-> decltype(std::forward<L>(l) << std::forward<R>(r))
{
return std::forward<L>(l) << std::forward<R>(r);
}
};
struct right_shift {
template <class L, class R>
constexpr auto operator()(L&& l, R&& r) const
noexcept(noexcept(std::forward<L>(l) >> std::forward<R>(r)))
-> decltype(std::forward<L>(l) >> std::forward<R>(r))
{
return std::forward<L>(l) >> std::forward<R>(r);
}
};
}
template<class X, class Y> using has_equality = op_valid<X, Y, std::equal_to<>>;
template<class X, class Y> using has_inequality = op_valid<X, Y, std::not_equal_to<>>;
template<class X, class Y> using has_less_than = op_valid<X, Y, std::less<>>;
template<class X, class Y> using has_less_equal = op_valid<X, Y, std::less_equal<>>;
template<class X, class Y> using has_greater_than = op_valid<X, Y, std::greater<>>;
template<class X, class Y> using has_greater_equal = op_valid<X, Y, std::greater_equal<>>;
template<class X, class Y> using has_bit_xor = op_valid<X, Y, std::bit_xor<>>;
template<class X, class Y> using has_bit_or = op_valid<X, Y, std::bit_or<>>;
template<class X, class Y> using has_left_shift = op_valid<X, Y, notstd::left_shift>;
template<class X, class Y> using has_right_shift = op_valid<X, Y, notstd::right_shift>;
int main()
{
assert(( has_equality<int, int>() ));
assert((not has_equality<std::string&, int const&>()()));
assert((has_equality<std::string&, std::string const&>()()));
assert(( has_inequality<int, int>() ));
assert(( has_less_than<int, int>() ));
assert(( has_greater_than<int, int>() ));
assert(( has_left_shift<std::ostream&, int>() ));
assert(( has_left_shift<std::ostream&, int&>() ));
assert(( has_left_shift<std::ostream&, int const&>() ));
assert((not has_right_shift<std::istream&, int>()()));
assert((has_right_shift<std::istream&, int&>()()));
assert((not has_right_shift<std::istream&, int const&>()()));
}
I know this question has long since been answered but I thought it might be worth noting for anyone who finds this question in the future that Boost just added a bunch of "has operator" traits to their type_traits library, and among them is has_equal_to, which does what OP was asking for.
This question has already been answered several times, but there is a simpler way to check for the existence of operator== or basically any other operation (e.g., testing for a member function with a certain name), by using decltype together with the , operator:
namespace detail
{
template<typename L, typename R>
struct has_operator_equals_impl
{
template<typename T = L, typename U = R> // template parameters here to enable SFINAE
static auto test(T &&t, U &&u) -> decltype(t == u, void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<L>(), std::declval<R>()));
};
} // namespace detail
template<typename L, typename R = L>
struct has_operator_equals : detail::has_operator_equals_impl<L, R>::type {};
You can use this same approach to check if a type T has a member function foo which is invocable with a certain argument list:
namespace detail
{
template<typename T, typename ...Args>
struct has_member_foo_impl
{
template<typename T_ = T>
static auto test(T_ &&t, Args &&...args) -> decltype(t.foo(std::forward<Args>(args)...), void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<T>(), std::declval<Args>()...));
};
} // namespace detail
template<typename T, typename ...Args>
struct has_member_foo : detail::has_member_foo_impl<T, Args...>::type {};
I think this makes the intent of the code much clearer. In addition to that, this is a C++11 solution, so it doesn't depend on any newer C++14 or C++17 features. The end result is the same, of course, but this has become my preferred idiom for testing these kinds of things.
Edit: Fixed the insane case of the overloaded comma operator, I always miss that.
Lets consider a meta-function of the following form, which checks for the existence of equality operator (i.e ==) for the given type:
template<typename T>
struct equality { .... };
However, that might not be good enough for some corner cases. For example, say your class X does define operator== but it doesn't return bool, instead it returns Y. So in this case, what should equality<X>::value return? true or false? Well, that depends on the specific use case which we dont know now, and it doesn't seem to be a good idea to assume anything and force it on the users. However, in general we can assume that the return type should be bool, so lets express this in the interface itself:
template<typename T, typename R = bool>
struct equality { .... };
The default value for R is bool which indicates it is the general case. In cases, where the return type of operator== is different, say Y, then you can say this:
equality<X, Y> //return type = Y
which checks for the given return-type as well. By default,
equality<X> //return type = bool
Here is one implementation of this meta-function:
namespace details
{
template <typename T, typename R, typename = R>
struct equality : std::false_type {};
template <typename T, typename R>
struct equality<T,R,decltype(std::declval<T>()==std::declval<T>())>
: std::true_type {};
}
template<typename T, typename R = bool>
struct equality : details::equality<T, R> {};
Test:
struct A {};
struct B { bool operator == (B const &); };
struct C { short operator == (C const &); };
int main()
{
std::cout<< "equality<A>::value = " << equality<A>::value << std::endl;
std::cout<< "equality<B>::value = " << equality<B>::value << std::endl;
std::cout<< "equality<C>::value = " << equality<C>::value << std::endl;
std::cout<< "equality<B,short>::value = " << equality<B,short>::value << std::endl;
std::cout<< "equality<C,short>::value = " << equality<C,short>::value << std::endl;
}
Output:
equality<A>::value = 0
equality<B>::value = 1
equality<C>::value = 0
equality<B,short>::value = 0
equality<C,short>::value = 1
Online Demo
Hope that helps.
c++17 slightly modified version of Richard Hodges godbolt
#include <functional>
#include <type_traits>
template<class T, class R, class ... Args>
std::is_convertible<std::invoke_result_t<T, Args...>, R> is_invokable_test(int);
template<class T, class R, class ... Args>
std::false_type is_invokable_test(...);
template<class T, class R, class ... Args>
using is_invokable = decltype(is_invokable_test<T, R, Args...>(0));
template<class T, class R, class ... Args>
constexpr auto is_invokable_v = is_invokable<T, R, Args...>::value;
template<class L, class R = L>
using has_equality = is_invokable<std::equal_to<>, bool, L, R>;
template<class L, class R = L>
constexpr auto has_equality_v = has_equality<L, R>::value;
struct L{};
int operator ==(int, L&&);
static_assert(has_equality_v<int>);
static_assert(!has_equality_v<L>);
static_assert(!has_equality_v<L, int>);
static_assert(has_equality_v<int, L>);
In addition to #coder3101 answer, concepts can help you implement any function existence tests you want to. For example, std::equality_comparable is implemented using 4 simple tests, that check the following scenarios:
For A and B variables, make sure that the following expressions are valid:
A == B, returns bool
A != B, returns bool
B == A, returns bool
B != A, returns bool
If any one of them is illegal at compile time, the program won't compile. The implementation of this test (simplified from the standard):
template <typename T> concept equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ t != u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
{ u != t } -> std::convertible_to<bool>;
};
As you can see, you can customize this concept and create your own concept the fulfill your conditions. For example, if you want to force only the existence of operator==, you can do something like this:
template <typename T> concept my_equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
};
Read more about concepts in C++20.
We can use std::equal_to<Type> (or any other overloaded struct members) to make a more generic solution if we want to test binary operators (or other binary functors).
struct No {};
template<class T, class BinaryOperator>
struct ExistsBinaryOperator>
{
enum { value = !std::is_same<decltype(std::declval<BinaryOperator>()(std::declval<T>(), std::declval<T>())), No>::value };
};
Usage:
using Type = int;
constexpr bool hasEqual = ExistsBinaryOperator<Type, std::equal_to<Type>>::value;
This should work on C++11
template <class Void, template<class...> class Type, class... Args>
struct validator
{
using value_t = std::false_type;
};
template <template<class...> class Type, class... Args>
struct validator< std::void_t<Type<Args...>>, Type, Args... >
{
using value_t = std::true_type;
};
template <template<class...> class Type, class... Args>
using is_valid = typename validator<void, Type, Args...>::value_t;
template<typename... T>
using has_equal_t = decltype((std::declval<T&>().operator ==(std::declval<T&>()), ...));
template<typename... T>
using has_gequal_t = decltype((operator ==(std::declval<T&>(),std::declval<T&>()), ...));
struct EQ
{
bool operator==(const EQ&) const;
};
struct GEQ
{
};
bool operator==(const GEQ&, const GEQ&);
struct NOEQ
{
};
static_assert(is_valid<has_equal_t,EQ>::value || is_valid<has_gequal_t,EQ>::value, "should have equal operator");
static_assert(is_valid<has_equal_t,GEQ>::value || is_valid<has_gequal_t,GEQ>::value, "should have equal operator");
// static_assert(is_valid<has_equal_t,NOEQ>::value || is_valid<has_gequal_t,NOEQ>::value, "should have equal operator"); // ERROR:
Just for a reference, I am posting how I solved my problem, without a need to check if the operator== exists :
#include <iostream>
#include <cstring>
struct A
{
int a;
char b;
#if 0
bool operator==( const A& r ) const
{
std::cout<<"calling member function"<<std::endl;
return ( ( a==r.a ) && ( b==r.b ) );
}
#endif
};
#if 1
bool operator==( const A &l,const A &r )
{
std::cout<<"calling NON-member function"<<std::endl;
return ( ( l.a==r.a ) &&( l.b==r.b ) );
}
#endif
namespace details
{
struct anyType
{
template < class S >
anyType( const S &s ) :
p(&s),
sz(sizeof(s))
{
}
const void *p;
int sz;
};
bool operator==( const anyType &l, const anyType &r )
{
std::cout<<"anyType::operator=="<<std::endl;
return ( 0 == std::memcmp( l.p, r.p, l.sz ) );
}
} // namespace details
int main()
{
A a1;
a1.a=3;a1.b=0x12;
A a2;
a2.a=3;a2.b=0x12;
using details::operator==;
std::cout<< std::boolalpha << "numbers are equals : " << ( a1 == a2 ) <<std::endl;
}
IMO, this must be part of the class itself as it's deals with the private attributes of the class. The templates are interpreted at compile time. By default it generates operator==,constructor, destructor and copy constructor which do bit-wise copy (shallow copy) or bit-wise comparisons for the object of same type. The special cases (different types) must be overloaded. If you use global operator function you will have to declare the function as friend to access the private part or else you've to expose the interfaces required. Sometimes this is really ugly which may cause an unnecessary expose of a function.
I have the code:
#include <unordered_set>
template<typename First, typename Enable = void, typename ... T>
class converged_is_exactly_equal_functor;
template<typename ... T>
bool converged_is_exactly_equal(const T& ...);
template <typename T, typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value>::type* = nullptr>
bool is_exactly_equal(const T other, const T one) {
return (other == one);
}
template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>
{
private:
static std::unordered_set<First*> visited_values;
void visit_value (const First& value_to_visit) {
visited_values.insert(&value_to_visit);
}
bool is_visited (const First& value_to_check) {
return (visited_values.find(&value_to_check) != visited_values.end());
}
public:
converged_is_exactly_equal_functor(void){}
bool operator () (const First& first_arg, const T& ... expanded_args) const {
if (!is_visited(first_arg)) {
visit_value(first_arg);
return is_exactly_equal(first_arg, expanded_args ...);
}
return true;
}
};
template<typename First, typename ... T>
std::unordered_set<First*> converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>::visited_values;
template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) != 1>, T ...>
{
public:
converged_is_exactly_equal_functor(void){}
bool operator () (const First& first_arg, const T& ... expanded_args) const {
return is_exactly_equal(first_arg, expanded_args ...);
}
};
template<typename ... T>
bool converged_is_exactly_equal(const T& ... expanded_args) {
converged_is_exactly_equal_functor<T ... > my_functor;
return my_functor(expanded_args ...);
}
class a {
public:
a() : dbid(1), lsb(123) {}
int dbid;
long lsb;
};
bool operator == (const a& other, const a& one) {
if (&other == &one)
return true;
return (
converged_is_exactly_equal(other.dbid, one.dbid) &&
converged_is_exactly_equal(other.lsb, one.lsb)
);
}
int main(void) {
a as, bs;
as == bs;
}
Given that class a is simple group of primitive types, why am I receiving the following error:
my_file.cxx: In instantiation of 'bool converged_is_exactly_equal(const T& ...) [with T = {long int, long int}]':
my_file.cxx:690:56: required from here
my_file.cxx:682:48: error: 'converged_is_exactly_equal_functor<long int, long int> my_functor' has incomplete type
converged_is_exactly_equal_functor<T ... > my_functor;
I believe the error has nothing to do with the proprietary data structures, but I don't see why the type could be incomplete. I have the header file for unordered_set included in this same file.
All definitions of is_exactly_equal(T) are done between the forward declarations and the templates' definitions.
Please be as explicit as possible, since I tend to find it complicated to understand template errors in general.
I can provide any more information necessary, but I'll only be back tomorrow. (This one has drained me out :-/)
The problem is in the converged_is_exactly_equal_functor class and in it's use.
You declare it as follows
template<typename First, typename Enable = void, typename ... T>
class converged_is_exactly_equal_functor;
without defining it.
Then you define two specializations: one for the case sizeof...(T) == 1
template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) == 1>, T ...>
{
// ...
};
and one for the case sizeof...(T) != 1
template<typename First, typename ... T>
class converged_is_exactly_equal_functor<First, std::enable_if<sizeof...(T) != 1>, T ...>
{
// ...
};
You use the class inside converged_is_exactly_equal
template<typename ... T>
bool converged_is_exactly_equal(const T& ... expanded_args) {
converged_is_exactly_equal_functor<T ... > my_functor;
return my_functor(expanded_args ...);
}
that is called, in your programs, two times
converged_is_exactly_equal(other.dbid, one.dbid) &&
converged_is_exactly_equal(other.lsb, one.lsb)
The first time with two int, the second time with two long.
In both case, you declare a converged_is_exactly_equal_functor value with a second template parameter that isn't void, so doesn't matches the specialization, so matches the main template but the main template is declared but not defined.
So the error.
A possible solution: throw away the SFINAE part and simply declare/define the class for a variadic list of following types (the old sizeof...(T) != 0)
template <typename F, typename ... Ts>
class converged_is_exactly_equal_functor
{
public:
converged_is_exactly_equal_functor ()
{ }
bool operator () (F const & fa, Ts const & ... ea) const
{ return is_exactly_equal(fa, ea ...); }
};
and define a specialization for two cases only (the old sizeof...(T) == 1 case)
template <typename First, typename Second>
class converged_is_exactly_equal_functor<First, Second>
{
private:
static std::unordered_set<First const *> visited_values;
void visit_value (First const & value_to_visit) const
{ visited_values.insert(&value_to_visit); }
bool is_visited (First const & value_to_check) const
{ return (visited_values.find(&value_to_check) != visited_values.end()); }
public:
converged_is_exactly_equal_functor ()
{ }
bool operator () (First const & fa, Second const & sa) const
{
if ( false == is_visited(fa) )
{
visit_value(fa);
return is_exactly_equal(fa, sa);
}
return true;
}
};
template <typename First, typename Second>
std::unordered_set<First const *> converged_is_exactly_equal_functor<First, Second>::visited_values;
Observe that I've added some const to let it compile.
I am trying to create an operator== operator for an std::variant defined in the map like this:
struct anyType
{
template<typename T>
void operator()(T t) const { std::cout << t; }
void operator()(const std::string& s) const { std::cout << '\"' << s << '\"'; }
};
template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, const& T t)
{
return v == t;
}
int main()
{
std::map<std::string, std::variant<float, int, bool, std::string>> kwargs;
kwargs["interface"] = "linear"s;
kwargs["flag"] = true;
kwargs["height"] = 5;
kwargs["length"] = 6;
//test
if (kwarg["interface"] == "linear") // stack overflow Error here
{
std::cout << true << '\n';
}
else
{
std::cout << false << '\n';
}
}
Can someone tell me why my operator isn't working?
You have a couple of issues in your code:
const &T t in your operator==, should be T const& t or const T& t.
You have forgotten to mention that you want to compare with a
std::string not with char array in your if statement(i.e. "linear"). Meaning you
need either of the followings:
if (kwargs["interface"] == std::string{ "linear" })
// or
using namespace std::string_literals;
if (kwargs["interface"] == "linear"s) // since C++14
When you do the comparison like this
if (kwargs["interface"] == "linear") // checking std::variant == char [7]
You are checking the std::variant<float, int, bool, std::string>(i.e. v) with type char [7](i.e. type of linear).
When the condition reaches the operator=='s definition you do again
the same by
return v == t; // checking std::variant == char [7]
This leads to a recursive call to the templated operator== itself
and hence stack overflow.
In order to fix, you needstrong text to explicitly specify the value from the variant either by index or by type. For example, chacking the type using std::is_same and if constexpr:
(See live online)
#include <type_traits> std::is_same_v
template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, T const& t)
{
if constexpr (std::is_same_v<T, float>) // float
return std::get<float>(v) == t;
else if constexpr (std::is_same_v<T, int>) // int
return std::get<int>(v) == t;
else if constexpr (std::is_same_v<T, bool>) // boolean
return std::get<bool>(v) == t;
else if constexpr (std::is_same_v<T, std::string>) // std::string
return std::get<std::string>(v) == t;
}
or simply (Credits #Barry)
template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, T const& t)
{
return std::get<T>(v) == t;
}
Now if you pass any other types other than v contains, you will get a compile-time error for the templated operator==.
Generic Solution!
For a generic std::varaint<Types...>, one can do as follows. In addition, it has been SFINAE d for only those types which are in the passed std::variant<Types>. I have used the is_one_of trait from this post.
(See Live Online)
#include <variant>
#include <type_traits>
// A trait to check that T is one of 'Types...'
template <typename T, typename...Types>
struct is_one_of final : std::disjunction<std::is_same<T, Types>...> {};
template<typename... Types, typename T>
auto operator==(const std::variant<Types...>& v, T const& t) noexcept
-> std::enable_if_t<is_one_of<T, Types...>::value, bool>
{
return std::get<T>(v) == t;
}
I'm trying to create a flags bitfield using C++11 enum classes. I'm looking for a way to templatize the operators' return types so they can be used as in code below:
#include <iostream>
enum class Flags {
one = 1,
two = 1 << 1,
three = 1 << 2,
four = 1 << 3
};
#define _CONVERT(_operator) \
static_cast<T>(static_cast<int>(lhs) _operator static_cast<int>(rhs))
template <typename T>
T operator & (const Flags& lhs, const Flags& rhs) {
return _CONVERT(&);
}
template <typename T>
T operator | (const Flags& lhs, const Flags& rhs) {
return _CONVERT(|);
}
#undef _convert
int main()
{
Flags flag = Flags::one | Flags::two | Flags::three;
if (flag & Flags::two)
std::cout << "Flag has two" << std::endl;
if (flag & Flags::four)
std::cout << "Flag has four" << std::endl;
std::cout << static_cast<int>(flag) << std::endl;
}
However, there are several problems:
Flags flag = Flags::one | Flags::two | Flags::three; can't deduce type to be Flags
if (flag & Flags::four) can't deduce type to be bool
I'm new to templates and am kinda lost when it comes to template deduction mechanisms. Also, i tried to create create conversion operator
operator bool(const Flags& flag)
but with no result.
First create a helper template:
template<class E>
struct bool_or_enum{
E e;
explicit operator bool()const{return static_cast<bool>(e); }
operator E() const {return e;}
};
Next, create a trait function and type:
namespace magic_operators {
template<class E>
constexpr std::false_type algebraic_enum(E const volatile&) {return {};}
template<class E>
using use_algebra=decltype( algebraic_enum( std::declval<E const volatile&>() ) );
}
Now magic_operators::use_algebra<E> searches using ADL for algebraic_enum overload returning std::true_type on E. This permits enabling the magic anywhere. MSVC 2015 lacks sufficient C++11 support to use the above; replace with traits class.
The meat: our operators. Stick them into a namespace and bring them in with using namespace:
template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator&(E const& lhs, E const& rhs){
using U = std::underlying_type_t<E>;
return { E( static_cast<U>(lhs) | static_cast<U>(rhs) ) };
}
And similar for |.
For ~ and ^ you need a bit mask to remain defined behaviour. Have a traits class enum_mask<E> that defaults to E::bit_mask or somesuch to get it.
template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator^(E const& lhs, E const& rhs){
using U = std::underlying_type_t<E>;
return { E( enum_mask<E>{} & (static_cast<U>(lhs) ^ static_cast<U>(rhs) ) ) };
}
template<class E, std::enable_if_t<magic_operators::use_algebra<E>{}, int> = 0>
bool_or_enum<E> operator~(E const& e){
using U = std::underlying_type_t<E>;
return { E( enum_mask<E>{} & (~static_cast<U>(e)) ) };
}
This is tricky due to standards requirements on out of gamut enums.
|= and &= isn't hard, but does need to be coded. = and |= and &= etc that support both assignment chaining and implicit bool requires yet more work. I say do not support it.
Oh and mark everything constexpr and add bool_or_enum<E> overloads to the operators.
The above code is not tested or compiled, but the design works.
The end result is:
enum class Bob { a=2, b=7, bit_mask = 0x00ff };
constexpr std::true_type algebraic_enum( Bob const& ){ return {}; }
using namespace algebraic_ops;
int main(){
Bob x=Bob::a;
x = x | Bob::b;
if( x &~ Bob::b ){
std::cout << "cast to bool bitmasking!\n";
}
}
Or somesuch.
While the #yakk-adam-nevraumont is nice and works, I preferred not to have to redefine anything for my enum classes, but rather have them to automatically get operators once I include my inline header...
So, I've done something like this:
#include <type_traits>
namespace EnumUtils {
template <typename T>
constexpr bool is_class() {
if constexpr (std::is_enum_v<T>) {
return !std::is_convertible_v<T, std::underlying_type_t<T>>;
}
return false;
}
template <class EnumType>
struct WrapperImpl {
EnumType e;
constexpr explicit WrapperImpl(EnumType const& en) : e(en) {}
constexpr explicit WrapperImpl(std::underlying_type_t<EnumType> const& en)
: e(static_cast<EnumType>(en)) {}
constexpr explicit operator bool() const { return static_cast<bool>(e); }
constexpr operator EnumType() const { return e; }
constexpr operator std::underlying_type_t<EnumType>() const {
return std::underlying_type_t<EnumType>(e);
}
};
template <class EnumType>
using Wrapper =
std::conditional_t<is_class<EnumType>(), WrapperImpl<EnumType>, void>;
} // namespace EnumUtils
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), Wrapped> operator&(
EnumType const& first, EnumType const& second) {
return static_cast<Wrapped>(static_cast<Wrapped>(first) &
static_cast<Wrapped>(second));
}
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), Wrapped> operator|(
EnumType const& first, EnumType const& second) {
return static_cast<Wrapped>(static_cast<Wrapped>(first) |
static_cast<Wrapped>(second));
}
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), Wrapped> operator^(
EnumType const& first, EnumType const& second) {
return static_cast<Wrapped>(static_cast<Wrapped>(first) ^
static_cast<Wrapped>(second));
}
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), Wrapped&> operator|=(
EnumType& first, // NOLINT(runtime/references)
EnumType const& second) {
first = (first | second);
return reinterpret_cast<Wrapped&>(first);
}
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), Wrapped&> operator&=(
EnumType& first, // NOLINT(runtime/references)
EnumType const& second) {
first = (first & second);
return reinterpret_cast<Wrapped&>(first);
}
template <class EnumType, class Wrapped = EnumUtils::Wrapper<EnumType>>
constexpr std::enable_if_t<EnumUtils::is_class<EnumType>(), EnumType> operator~(
EnumType const& first) {
return static_cast<EnumType>(~static_cast<Wrapped>(first));
}
I am a newer for C++, and my first language is Chinese, so my words with English may be unmeaningful, say sorry first.
I know there is a way to write a function with variable parameters which number or type maybe different each calling, we can use the macros of va_list,va_start and va_end. But as everyone know, it is the C style. When we use the macros, we will lose the benefit of type-safe and auto-inference, then I try do it whit C++ template. My work is followed:
#include<iostream>
#include<vector>
#include<boost/any.hpp>
struct Argument
{
typedef boost::bad_any_cast bad_cast;
template<typename Type>
Argument& operator,(const Type& v)
{
boost::any a(v);
_args.push_back(a);
return *this;
}
size_t size() const
{
return _args.size();
}
template<typename Type>
Type value(size_t n) const
{
return boost::any_cast<Type>(_args[n]);
}
template<typename Type>
const Type* piont(size_t n) const
{
return boost::any_cast<Type>(&_args[n]);
}
private:
std::vector<boost::any> _args;
};
int sum(const Argument& arg)
{
int sum=0;
for(size_t s=0; s<arg.size(); ++s)
{
sum += arg.value<int>(s);
}
return sum;
}
int main()
{
std::cout << sum((Argument(), 1, 3, 4, 5)) << std::endl;
return 0;
}
I think it's ugly, I want to there is a way to do better? Thanks, and sorry for language errors.
You can do something like this:
template <typename T>
class sum{
T value;
public:
sum ()
: value() {};
// Add one argument
sum<T>& operator<<(T const& x)
{ value += x; return *this; }
// to get funal value
operator T()
{ return value;}
// need another type that's handled differently? Sure!
sum<T>& operator<<(double const& x)
{ value += 100*int(x); return *this; }
};
#include <iostream>
int main()
{
std::cout << (sum<int>() << 5 << 1 << 1.5 << 19) << "\n";
return 0;
}
Such technique (operator overloading and stream-like function class) may solve different problems with variable arguments, not only this one. For example:
create_window() << window::caption - "Hey" << window::width - 5;
// height of the window and its other parameters are not set here and use default values
After giving it some thought, I found a way to do it using a typelist. You don't need an any type that way, and your code becomes type-safe.
It's based on building a template structure containing a head (of a known type) and a tail, which is again a typelist. I added some syntactic sugar to make it more intuitive: use like this:
// the 1 argument processing function
template< typename TArg > void processArg( const TArg& arg ) {
std::cout << "processing " << arg.value << std::endl;
}
// recursive function: processes
// the first argument, and calls itself again for
// the rest of the typelist
// (note: can be generalized to take _any_ function
template< typename TArgs >
void process( const TArgs& args ) {
processArg( args.head );
return process( args.rest );
}
template<> void process<VoidArg>( const VoidArg& arg ){}
int main() {
const char* p = "another string";
process( (arglist= 1, 1.2, "a string", p ) );
}
And here is the argument passing framework:
#include <iostream>
// wrapper to abstract away the difference between pointer types and value types.
template< typename T > struct TCont {
T value;
TCont( const T& t ):value(t){}
};
template<typename T, size_t N> struct TCont< T[N] > {
const T* value;
TCont( const T* const t ) : value( t ) { }
};
template<typename T> struct TCont<T*> {
const T* value;
TCont( const T* t ): value(t){}
};
// forward definition of type argument list
template< typename aT, typename aRest >
struct TArgList ;
// this structure is the starting point
// of the type safe variadic argument list
struct VoidArg {
template< typename A >
struct Append {
typedef TArgList< A, VoidArg > result;
};
template< typename A >
typename Append<A>::result append( const A& a ) const {
Append<A>::result ret( a, *this );
return ret;
}
//syntactic sugar
template< typename A > typename Append<A>::result operator=( const A& a ) const { return append(a); }
} const arglist;
// typelist containing an argument
// and the rest of the arguments (again a typelist)
//
template< typename aT, typename aRest >
struct TArgList {
typedef aT T;
typedef aRest Rest;
typedef TArgList< aT, aRest > Self;
TArgList( const TCont<T>& head, const Rest& rest ): head( head ), rest( rest ){}
TCont<T> head;
Rest rest;
template< typename A > struct Append {
typedef TArgList< T, typename Rest::Append<A>::result > result;
};
template< typename A >
typename Append< A >::result append( const A& a ) const {
Append< A >::result ret ( head.value, (rest.append( a ) ) );
return ret;
}
template< typename A > typename Append<A>::result operator,( const A& a ) const { return append(a); }
};