For example, I have two classes:
class Foo {
public:
const bool operator==(const Foo&) const;
template<class _Ty>
const bool operator==(const _Ty&) const;
};
class Bar : public Foo { };
And code like this:
Foo& foo;
Bar& bar;
const bool equality = (foo == bar);
Obviously, a compiler will choose the template function to evaluate this expression because variable bar need to be converted to Foo& to call the specialized operator==. But is there any way how I can force a compiler (without casting Bar& into Foo&) to choose the specialization firstly instead of the template function when the argument is an instance of a class derived from Foo (e.g. add/remove some modifiers or something else)?
Is there any way how I can force a compiler (without casting Bar& into Foo&) to choose the specialization firstly instead of the template function when the argument is an instance of a class derived from Foo?
Yes, you can, using type traits. Specifically you can use std::enable_if and std::is_base_of as follows:
template<typename Type>
typename std::enable_if<
std::is_base_of<Foo, Type>::value,
const bool
>::type
operator==(const Type&) const { … }
template<typename Type>
typename std::enable_if<
!std::is_base_of<Foo, Type>::value,
const bool
>::type
operator==(const Type&) const { … }
Live demo
You basically activate/deactivate an overload based on template argument.
You can also make things slightly more readable by adding an alias:
template<class Type>
using is_fooable = std::is_base_of<Foo, Type>;
Live demo
Related
I have the following class structure:
template <typename...>
class SomeClass {
public:
class Foo { };
class Bar { };
};
I need to define operator== for SomeClass<Ts...>::Foo and SomeClass<Ts...>::Bar and I need to make it a friend of both Foo and Bar. The closest I got this to working is the following:
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
friend bool operator==(const Foo&, const Bar&) {
return true;
}
};
class Bar {
friend bool operator==(const Foo&, const Bar&);
};
};
Then I do:
SomeClass<int, double>::Foo foo;
SomeClass<int, double>::Bar bar;
foo == bar;
This compiles and works fine except for the fact that gcc gives me the warning:
warning: friend declaration `bool operator==(const SomeClass<Args>::Foo&, const SomeClass<Args>::Bar&)` declares a non-template function
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
I kind of understand why this happens (operator== indeed depends on the template parameters of SomeClass), but how do I get rid of it? Adding <> to the second friend declaration, as suggested, only breaks compilation: the friending is no longer recognized and the compiler complaints about access to a private member.
I tried to modify the code according to the template friend declaration guide, but that only made things worse:
template <typename...>
class SomeClass;
template <typename... Args>
bool operator==(const typename SomeClass<Args...>::Foo&,
const typename SomeClass<Args...>::Bar&);
template <typename... Args>
class SomeClass {
public:
class Bar;
class Foo {
friend bool operator==<Args...>(const Foo&, const Bar&);
};
class Bar {
friend bool operator==<Args...>(const Foo&, const Bar&);
};
};
template <typename... Args>
bool operator==(const typename SomeClass<Args...>::Foo&,
const typename SomeClass<Args...>::Bar&) {
return true;
}
Now the weirdest thing happens when I call foo == bar:
error: no match for ‘operator==’ (operand types are ‘SomeClass<int, double>::Foo’ and ‘SomeClass<int, double>::Bar’)
note: candidate: ‘bool operator==(const typename SomeClass<Args ...>::Foo&, const typename SomeClass<Args ...>::Bar&) [with Args = {}; typename SomeClass<Args ...>::Foo = SomeClass<>::Foo; typename SomeClass<Args ...>::Bar = SomeClass<>::Bar]’ (reversed)
note: no known conversion for argument 1 from ‘SomeClass<int, double>::Bar’ to ‘const SomeClass<>::Foo&’
I.e. for some weird reason it tries to call the template specification with an empty arguments list and fails. Changing the operator type (to operator+) doesn't help (my idea was, this had something to do with C++20 new rules for comparison operators, but no).
So the questions I have are:
What's going on? I'm kind of confused, especially by the second part: why would the compiler try to call the operator for an empty parameter pack?
How do I avoid the warning in the first solution?
How do I define the operator outside of the class definition properly?
Ok, here are the results of some research I did.
In case of the friend in-class definition, according to cppreference, what it does is it generates non-template overloads of operator==. Thus, it is perfectly fine to reference them from the second friend declaration, and the code itself is correct. This is also why adding "<>" breaks the befriending: the overloads generated by the first definition are not template functions, while the second definition with the "<>" added now refers to some template overload that isn't definded.
Both Clang and MSVC compile that code without any problems, so the warning seems to be a GCC-only thing. I think, it is ok to suppress it.
The alternative would be to make the operator into a template, but unfortunately doing this properly for the parent class template parameters is impossible. This won't compile (see below why):
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
template <typename... Ts>
friend bool operator==(const typename SomeClass<Ts...>::Foo&,
const typename SomeClass<Ts...>::Bar&) {
return true;
}
};
class Bar {
template <typename... Ts>
friend bool operator==(const typename SomeClass<Ts...>::Foo&,
const typename SomeClass<Ts...>::Bar&);
};
};
The real alternative here is to trick GCC by making the operator template with some obsolete arguments, that could be deduced. And since default template arguments are forbidden in friend declarations, the only other hack I can think of is to make the operator variadic and use the fact that a trailing parameter pack that is not otherwise deduced, is deduced to an empty parameter pack. This works and emits no warnings in GCC:
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
template <typename...>
friend bool operator==(const Foo&, const Bar&) {
return true;
}
};
class Bar {
template <typename...>
friend bool operator==(const Foo&, const Bar&);
};
};
I really see no reason in doing that now, so the best thing to do is to pretend that you never saw this, and that I never wrote this.
Now, the second part, the outside definition. The problem here is that, as it turns out, there is no way in C++ to deduce template arguments (pack or not) of a parent class from a nested class.
I.e. a thing like this cannot possibly work:
template <typename T>
void foo(typename Parent<T>::Child) { }
foo(Parent<int>::Child{});
There even was a proposal to resolve this issue, but it was declined.
Defining operator== as a template function in my example above has exactly this problem: once the operator is called for SomeClass<int, double>::Foo and SomeClass<int, double>::Bar, the argument deduction is impossible (though the definition itself is correct), thus the compilation fails. This is also the answer to my first question: since the deduction is impossible, a parameter pack is deduced as an empty pack. Not at all what I intended.
The only workaround I came up with is to define the operator for the template non-nested arguments, and then restrict them. I am going to use C++20 concepts for this, although I think a SFINAE solution could be just as fine.
This works exactly as intended:
template <typename...>
class SomeClass;
template <typename T>
constexpr bool IsSomeClass = false;
template <typename... Args>
constexpr bool IsSomeClass<SomeClass<Args...>> = true;
template <typename T, typename U>
concept IsProperFooBar = requires {
typename T::Parent;
typename U::Parent;
requires std::same_as<typename T::Parent, typename U::Parent>;
requires IsSomeClass<typename T::Parent>;
requires std::same_as<std::decay_t<T>, typename T::Parent::Foo>;
requires std::same_as<std::decay_t<U>, typename U::Parent::Bar>;
};
template <typename T, typename U> requires IsProperFooBar<T, U>
bool operator==(const T&, const U&);
template <typename... Args>
class SomeClass {
public:
class Foo {
public:
using Parent = SomeClass;
private:
template <typename T, typename U> requires IsProperFooBar<T, U>
friend bool operator==(const T&, const U&);
};
class Bar {
public:
using Parent = SomeClass;
private:
template <typename T, typename U> requires IsProperFooBar<T, U>
friend bool operator==(const T&, const U&);
};
};
template <typename T, typename U> requires IsProperFooBar<T, U>
bool operator==(const T&, const U&) {
return true;
}
The only issue I see with this solution is that there is now a universal template operator==, so the concept will be checked every time you call == for anything, which may slow down compilation and emit unnecessary concept-not-satisfied diagnostic messages for other things.
On the plus side, there is no need in forward-declaring class Bar anymore, so at least I got that going for me, which is nice :-)
I got this solution with operator=='s definition outside the class.
There is no warning now, but I had to remove the friend qualifier. In order to access Foo's private methods from Bar's functions, declare Bar a friend of Foo (inside Foo). Do likewise for Bar if you want to access Bar's members from within Foo's methods.
Perhaps its a step forward. Hopes this helps.
#include <iostream>
template <typename... Args>
class SomeClass {
public:
class Bar;
class Foo;
class Foo {
public:
friend Bar;
bool operator==(const Bar&) const;
void do_something_to_Bar(Bar&);
private:
int _foo;
};
class Bar {
public:
friend Foo;
bool operator==(const Foo&) const;
void do_something_to_Foo(Foo&);
private:
int _bar;
};
};
template<typename... Args>
bool SomeClass<Args...>::Foo::operator== (const Bar& b) const {
return b._bar == _foo;
}
template<typename... Args>
bool SomeClass<Args...>::Bar::operator== (const Foo& f) const {
return f == *this;
}
template<typename... Args>
void SomeClass<Args...>::Bar::do_something_to_Foo(Foo& f) {
f._foo = 4;
_bar = 4;
}
template<typename... Args>
void SomeClass<Args...>::Foo::do_something_to_Bar(Bar& b) {
b._bar = 4;
_foo = 3;
}
int main() {
SomeClass<int,float>::Foo foo;
SomeClass<int,float>::Bar bar;
foo.do_something_to_Bar(bar);
std::cout << (foo == bar) << '\n';
std::cout << (bar == foo) << '\n';
bar.do_something_to_Foo(foo);
std::cout << (foo == bar) << '\n';
std::cout << (bar == foo) << '\n';
}
The definition of SomeClass<Args...>::Bar::operator== does not redefine the operator, but rather uses the definition of SomeClass<Args...>::Foo::operator==.
This is a model case where there is a generic function func and then (humanely speaking) more specialized function func for classes deriving from Base via CRTP, which is only enabled for appropriate argument type via enable_if.
#include<type_traits>
#include<iostream>
// CRTP hierarchy
template<class T> class Base{ };
class Derived: public Base<Derived>{};
// overload 1
template<class T> void func(const T& a){ std::cerr<<"1\n"; }
// overload 2
template<class T, typename std::enable_if<std::is_base_of<Base<T>,T>::value,int>::type* = nullptr>
inline void func(const Base<T>& obj){ std::cerr<<"2\n"; }
int main(void){ func(Derived()); }
The compiler still thinks, however, that the first overload is a better match. I understand that enable_if only enables the function but does not make it better for the overload resolution.
I am sorry to say I was not able to make much sense from Function template section of c++ reference.
Can anyone give an advise how to make compiler prefer the second function?
Thanks!
Edit: MOTIVATION: In the real use, those functions should handle various scalar and array types (Eigen, in particular, which is using CRTP). Scalars should cover all numeric types like ints, floats, ... (without enumerating them) and the other overload should cover arrays — again, without enumerating them, but knowing all of them derive from Eigen::DenseBase<Derived>.
Just use constexpr ifs to select the correct function from a single public function.
C++17
namespace
{
template<typename T>
inline void base_func( const T& derived );
template<typename T>
inline void other_func( const T& otherType );
}
template<typename T>
inline void func( const T& type )
{
if constexpr( std::is_base_of_v<Base<T>, T> )
base_func( type );
else
other_func( type );
}
C++14 Using traits
namespace
{
template<typename T>
inline void base_func( const T& derived );
template<typename T>
inline void other_func( const T& otherType );
template <bool B>
struct func_select_trait;
template <>
struct func_select_trait<true>
{
template <typename T>
static void call( const T& derived ) { base_func<T>( derived ); }
};
template <>
struct func_select_trait<false>
{
template <typename T>
static void call( const T& otherType ) { other_func<T>( otherType ); }
};
}
template<typename T>
inline void func( const T& type )
{
func_select_trait<std::is_base_of<Base<T>, T>::value>::call<T>( type );
}
The 2 overloads are viables
overload 1. has exact match
overload 2. has derived to base conversion
See:
https://en.cppreference.com/w/cpp/language/overload_resolution#Ranking_of_implicit_conversion_sequences for more details
You might SFINAE the first overload:
// overload 1
template <class T, std::enable_if_t<!std::is_base_of_v<Base<T>, T>, int> = 0>
void func(const T& a){ std::cerr<<"1\n"; }
Demo
I'm trying to find a way to simply check if a method of a given name exists in a c++ class using c++11 features, but without(!) checking the signature.
I was unable to find anything without the signature check, so I tried to use Valentin Milea's solution from here and modify it (see below), but my understanding of c++ is not deep enough to really grasp what's going on there:
#include <type_traits>
template <class C>
class HasApproxEqualMethod
{
template <class T>
static std::true_type testSignature(bool (T::*)(const T&, double) const);
template <class T>
static decltype(testSignature(&T::approx_equal)) test(std::nullptr_t);
template <class T>
static std::false_type test(...);
public:
using type = decltype(test<C>(nullptr));
static const bool value = type::value;
};
class Base {
public:
virtual ~Base();
virtual bool approx_equal(const Base& other, double tolerance) const;
};
class Derived : public Base {
public:
// same interface as base class
bool approx_equal(const Base& other, double tolerance) const;
};
class Other {};
static_assert(HasApproxEqualMethod<Base>().value == true, "fail Base");
static_assert(HasApproxEqualMethod<Other>().value == false, "fail Other");
// this one fails:
static_assert(HasApproxEqualMethod<Derived>().value == true, "fail Derived");
I think the root of the problem is that my approx_equal uses base class references also in the derived class(es) and that doesn't match the signature anymore.
In the end, I want to construct a template comparison function that calls approx_equal if it exists, or something else( e.g. == for strings etc., or fabs(a-b) <= tolerance for floats and doubles). The approx_equal functions will then in turn call the template comparison for each member.
I actually got that part to work with an ugly workaround, where each class with an approx_equal method also gets a member variable const static char hasApproxEqualMethod. Then I check if that variable exists as suggested here, but that's certainly not the way to go.
What about using std::is_member_function_pointer_v (requires c++17):
// Works
static_assert(std::is_member_function_pointer_v<decltype(&Base::approx_equal)>);
// Works
static_assert(std::is_member_function_pointer_v<decltype(&Derived::approx_equal)>);
// Fails as expected
static_assert(!std::is_member_function_pointer_v<decltype(&Other::approx_equal)>);
You can shorten it like this:
template<typename Class>
constexpr bool has_approx_equal()
{
return std::is_member_function_pointer_v<decltype(&Class::approx_equal)>;
}
static_assert(has_approx_equal<Base>());
static_assert(has_approx_equal<Derived>());
static_assert(!has_approx_equal<Other>());
Final solution uses SFINAE so that the compilation doesn't abort when tring to evaluate &Other::approx_equal:
template<typename Class, typename Enabled = void>
struct has_approx_equal_s
{
static constexpr bool value = false;
};
template<typename Class>
struct has_approx_equal_s
<
Class,
std::enable_if_t
<
std::is_member_function_pointer_v<decltype(&Class::approx_equal)>
>
>
{
static constexpr bool value = std::is_member_function_pointer_v<decltype(&Class::approx_equal)>;
};
template<typename Class>
constexpr bool has_approx_equal()
{
return has_approx_equal_s<Class>::value;
};
static_assert(has_approx_equal<Base>());
static_assert(has_approx_equal<Derived>());
static_assert(has_approx_equal<Other>(), "Other doesn't have approx_equal.");
SFINAE makes sure it is possible to get false value before trying to evaluate the static assertion.
The problem in your code is that you check that a class has method that accept, as first argument a constant reference to an object of the same class
template <class T>
static std::true_type testSignature(bool (T::*)(const T&, double) const);
// .......................................^...........^ same class
but inside Derived you define a method that receive an object of a different class (Base)
// ...VVVVVVV object is Derived
class Derived : public Base {
public:
// same interface as base class
bool approx_equal(const Base& other, double tolerance) const;
// .....................^^^^ method accept Base
};
A possible solution is relax the test in HasApproxEqualMethod to accept also objects of different classes
template <class T, class U>
static std::true_type testSignature(bool (T::*)(const U&, double) const);
// now class and argument are different...^...........^
This way is satisfied also
static_assert(HasApproxEqualMethod<Derived>().value == true, "fail Derived");
If you want avoid at all the signature check, you can try something similar
template <typename T>
constexpr auto haemHelper (T const &, int)
-> decltype( &T::approx_equal, std::true_type{} );
template <typename T>
constexpr std::false_type haemHelper (T const &, long);
template <typename T>
using HasApproxEqualMethod = decltype( haemHelper(std::declval<T>(), 0) );
but, this way, HasApproxEqualMethod<T> is std::true_type also when T has a approx_equal method with a completely different signature or also when approx_equal is a simple member (a variable).
check if a method of a given name exists in a c++ class using c++11 features, but without(!) checking the signature.
[..]
In the end, I want to construct a template comparison function that calls approx_equal if it exists
In fact, you want to know if bool(lhs.approx_equal(rhs, some_double)) is valid, so not exact signature, but "compatible" signature. and it is use to dispatch along overloads.
So, you may use decltype and order your overloads:
// helper function to prioritize overload. bigger has more priority
template <std::size_t N> struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {}; // Lowest priority
// member function
template <typename T>
auto generic_approx_equal_impl(const T& lhs, const T& rhs, double tolerance, overload_priority<2>)
-> decltype(bool(lhs.approx_equal(rhs, tolerance))
{
return lhs.approx_equal(rhs, tolerance);
}
// free function
template <typename T>
auto generic_approx_equal_impl(const T& lhs, const T& rhs, double tolerance, overload_priority<2>)
-> decltype(bool(approx_equal(lhs, rhs, tolerance))
{
return approx_equal(lhs, rhs, tolerance);
}
// fallback
template <typename T>
bool generic_approx_equal_impl(const T& lhs, const T& rhs, double tolerance, overload_priority<0>)
{
/*..*/
//return abs(lhs - rhs) < tolerance;
return false;
}
template <typename T>
bool generic_approx_equal(const T& lhs, const T& rhs, double tolerance)
{
// Call with number greater or equal to max overloads
return generic_approx_equal_impl(lhs, rhs, tolerance, overload_priority<10>{});
}
I prefer to write definitions for class and function templates in a separate file which is automatically included after the "public" header. However, I've come to an interesting case where it looks like I can't do that.
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
int main()
{
Type a;
Type b;
a == b;
}
Is it possible to write definition of operator== separately that will work for any T and U?
For a particular specialization, yes:
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
int x = 42;
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
bool operator ==(const Type& lhs, const Type& rhs) {
return lhs.x == rhs.x;
}
int main()
{
Type a;
Type b;
a == b;
}
In your example, each specialization of the template befriends a non-template function that takes that particular specialization as parameters. You could define this function in-class (and then it will be stamped out every time the template is instantiated), or you could define it out-of-class - but then you would have to define one for every specialization you ever use.
As Igor Tandetnik points out, your example declares a non-template friend function, which you'll have to overload for each template instantiation, which is one reason friend functions are allowed to be defined inline (so they can be generated by the template without having to be templates themselves).
If you want to define the friend function as a template, here is the closest I was able to come up with:
template <typename T>
struct Outer {
template <typename U>
struct Inner;
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );
template <typename T>
template <typename U>
struct Outer<T>::Inner {
friend bool operator==<T,U>(Inner const &, Inner const &);
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
return true;
}
// I switched this out, because my gcc-4.6 doesn't
// understand "using" aliases like this yet:
typedef Outer<int>::Inner<short> Type;
int main() {
Type a;
Type b;
operator==<int,short>( a, b );
}
Unfortunately, you'll notice the call site of this operator function is very awkward: operator==<int,short>( a, b ). I believe defining a function template on a nested class template like this disables (or at least interferes with) argument deduction, so you have to specify the template parameters explicitly (which means calling it as a function rather than in operator form). This is why the inline friend definition is so convenient. If you really want to define your operator=='s code separately, I'd recommend defining the friend inline to call another function template (with the proper template arguments), which you can then define out-of-line as a free function.
I want to specialize following member function:
class foo {
template<typename T>
T get() const;
};
To other class bar that depends on templates as well.
For example, I would like bar to be std::pair with some template parameters, something like that:
template<>
std::pair<T1,T2> foo::get() const
{
T1 x=...;
T2 y=...;
return std::pair<T1,T2>(x,y);
}
Where T1 and T2 are templates as well. How can this be done? As far as I know it should be
possible.
So now I can call:
some_foo.get<std::pair<int,double> >();
The full/final answer:
template<typename T> struct traits;
class foo {
template<typename T>
T get() const
{
return traits<T>::get(*this);
}
};
template<typename T>
struct traits {
static T get(foo &f)
{
return f.get<T>();
}
};
template<typename T1,typename T2>
struct traits<std::pair<T1,T2> > {
static std::pair<T1,T2> get(foo &f)
{
T1 x=...;
T2 y=...;
return std::make_pair(x,y);
}
};
You can't partially specialize function templates, sorry but those are the rules. You can do something like:
class foo {
...
};
template<typename T>
struct getter {
static T get(const foo& some_foo);
};
template<typename T1, typename T2>
struct getter< std::pair<T1, T2> > {
static std::pair<T1, T2> get(const foo& some_foo) {
T1 t1 = ...;
T2 t2 = ...;
return std::make_pair(t1, t2);
};
and then call it like
getter<std::pair<int, double> >::get(some_foo);
though. You may have to do some messing around with friendship or visibility if get really needed to be a member function.
To elaborate on sbi's suggestion:
class foo {
...
template<typename T>
T get() const;
};
template<typename T>
T foo::get() const
{
return getter<T>::get(*this);
/* ^-- specialization happens here */
}
And now you're back to being able to say
std::pair<int,double> p = some_foo.get<std::pair<int, double> >();
You need to overload your member function for pair, like in
template <T, V> std::pair<T, V> foo::get()
In the general case you will need to be able to disambiguate between the various overloads. In the case disambiguation is easy because pair is templated on 2 types while the original member was templated on T only.
If instead you needed a specialization for, e.g., std::vector, that is for a container with a single parameter template, you have to be careful since given it can be confusing for the compiler to understand if you wish to instantiate the template specialization where the template T is std::vector or the specialization for the overload,
template <T> std::<vector <T> foo::get() const
Your proposed syntax cannot work since you are completely specializing the member function,
template <>,
but you are leaving out two unspecified types, T1 and T2.