Overriding a templated function with a polymorphic one - c++

If I have
template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override
and a class
class A : public TalkySerialisable {
...}
Then if I perform
TalkyBuffer b;
A test;
b << test;
Then gcc is calling the Template function rather than the Override function
However if I specifically define an override
TalkyBuffer& operator<<(A const &object); // Override without polymorphism
Then gcc picks that one.
Is there a practical way to override a templated function with an abstract class?
I read this but it doesn't shed light onto what happens when you throw polymorphism into the mix:
http://www.gotw.ca/publications/mill17.htm
Also I couldn't find a solution here but perhaps I'm using the wrong terms.

When defining the function TalkyBuffer& operator<<(TalkySerialisable const &object); You are not overriding. You are overloading the tmeplated function.
But, when the complier sees b << test;, it searches for an operator that wants an A. It has one, it's the templated function that requires no automatic cast. This is the best choice.
The overloaded function requires an automatic cast (from A to TalkySerialisable) on the parameters to fit the declaration, and is not the best choice.

I think it's possible to use a simple function based solution, reusing function overload for derivation.
struct specialized {};
struct generic {};
template <class T>
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) {
...
}
generic dispatch(...) {} // always picked up last in overload resolution
template <class T>
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template
return serialize(*this, object, dispatch(object));
}
Now, let's implement your custom class:
TalkyBuffer& serialize(TalkyBuffer& buffer,
TalkySerialisable const& object,
specialized);
specialized dispatch(TalkySerialisable const&) {}
And create a derived one:
class A: public TalkySerialisable {};
So, what happens ?
TalkyBuffer::operator<<(T const&) will be picked up
when trying to resolve the overload for serialize, it will first compute the result of dispatch
when resolving the result of dispatch, dispatch(TalkySerializable const&) is a better match than dispath(...), thus the return type is specialized
the generic serialize cannot be used (there is no conversion from specialized to generic), so inheritance kicks in

A solution using Boost.enable_if:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
template<typename T>
typename boost::disable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object) { // Template for non TalkySerializable
...
}
template <typename T>
typename boost::enable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object); // Template overload for TalkySerializable
...
TalkyBuffer b;
A test;
b << test; // calls operator<< <A>(A const &), which instantiates
// the overload for TalkySerializable
b << 41; // calls operator<< <int>(int const &), which corresponds to
// the "default" overload
I'm not sure this is the best solution, but I failed to find a better one: specializing the template does not work either.
As #Matthieu noted in the comment, the previous solution has the major drawback that the base template needs to know that it will be overloaded, which is an unnecessary coupling that hinders extensibility.
To solve this problem, I came up with a new approach using tag dispatching, along with trait classes and compile-time introspection using Boost.MPL macros.
// TalkyBuffer.hpp
#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/has_xxx.hpp>
// defines a metafunction has_talky_buffer_tag<T> that allows us to know at
// compile-time if T has a member type named talky_buffer_tag
BOOST_MPL_HAS_XXX_TRAIT_DEF(talky_buffer_tag)
// tag for the default case
struct default_talky_buffer_tag {};
// trait class for obtaining the tag of a type
template <typename T, typename Enable = void >
struct talky_buffer_trait
{
typedef default_talky_buffer_tag type;
};
// specialization for types that provide a nested typedef
template <typename T>
struct talky_buffer_trait<T,
typename boost::enable_if<has_talky_buffer_tag<T> >::type>
{
typedef typename T::talky_buffer_tag type;
};
struct TalkyBuffer
{
// Insertion operator, which calls an implementation function that can
// be overloaded depending on the tag
template<typename T>
TalkyBuffer & operator<<(T const & object)
{
typename talky_buffer_trait<T>::type tag;
return insertionOperatorImpl(*this, object, tag);
}
};
// default implementation
template <typename T>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, T const & object,
default_talky_buffer_tag)
{
std::cout << "default";
return buf;
}
//-------
// TalkySerializable.hpp
struct TalkySerializable
{
struct tag {};
typedef tag talky_buffer_tag;
};
// A inherits from the nested typedef
struct A : public TalkySerializable {};
// implementation for TalkySerializable objects
template <typename Serializable>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, Serializable const & object,
TalkySerializable::tag)
{
std::cout << "specialized";
return buf;
}
//-------
int main()
{
TalkyBuffer b;
A test;
b << test; // outputs "specialized"
b << 41; // outputs "default"
}
To provide new implementations of the insertion operator for a given type T, one needs to provide a new type to act as a tag (TypeSerializable::tag in our example), provides a way to associate T with the new tag (either by using a nested typedef as in the example, or by specializing the trait class: template <> talky_buffer_trait<T> { typedef new_tag type };), and finally overload the implementation function (insertionOperatorImpl in the example).

Related

Hash an object using its base class' partial template specialization for std::hash

I have a wrapper class for std::string that serves as base class for several others. Instances of the subclasses will be used as keys in std::unordered_set so I need to provide a hash function for them. Since the hash is only dependent on the std::string stored in the base class, I do not want to write a hash function for every subclass but rather use the one from the wrapper class.
This is how I would like to solve the problem:
#include <string>
#include <unordered_set>
class Wrapper {
public:
std::string name;
size_t _hash;
explicit Wrapper(std::string str) : name(str), _hash(std::hash<std::string>()(name)) {}
size_t hash() const { return _hash; }
};
class Derived : public Wrapper {};
namespace std {
template <> struct hash<Wrapper> {
std::size_t operator()(const Wrapper &k) const { return k.hash(); }
};
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
std::size_t operator()(const T &k) const { return k.hash(); }
};
} // namespace std
int main(void) {
std::unordered_set<Wrapper> m1;
std::unordered_set<Derived> m2;
}
This does not compile of course, since T cannot be deduced. Clang says:
20:30: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
20:20: note: non-deducible template parameter 'T'
And g++ says:
hash_subclass.cpp:21:30: error: template parameters not deducible in partial specialization:
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hash_subclass.cpp:21:30: note: 'T'
I have found this solution, but I would like to avoid using a macro. Also, this goes against what I expect from inheritance.
Is there a solution for this? Can a subclass inherit its base class' specialization of std::hash?
Also, I'm not 100% sure about my use of std::enable_if and std::is_base_of. Could you tell me whether this would work assuming T could be deduced?
IRC, the problem with std::enable_if is that it does not work for classes with a single template parameter. Consequently, you cannot specialize std::hash by using std::enable_if.
However, you can make your own hasher as follows:
template <typename T, typename Enable = std::enable_if_t<std::is_base_of_v<Wrapper, T>>>
struct WrapperHasher {
std::size_t operator()(const T& k) const { return k.hash(); }
};
And then use it as a second template argument of std::unordered_set:
std::unordered_set<Wrapper, WrapperHasher<Wrapper>> m1;
std::unordered_set<Derived, WrapperHasher<Derived>> m2;
But in your case, you can define a wrapper much more simply as:
struct WrapperHasher {
std::size_t operator()(const Wrapper& k) const { return k.hash(); }
};
And then write:
std::unordered_set<Wrapper, WrapperHasher> m1;
std::unordered_set<Derived, WrapperHasher> m2;

avoid pointer-to-member-function for non-class type

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).

How do I use the "Barton–Nackman trick" to implement trival methods?

Inspired of boost::operators I thought the Barton-Nackman idiom could be used to implement from trival member methods.
Following is what I have tried (does not compile)
template<typename T>
class impl_get_set {
typename T::storage_type get() const {
return static_cast<const T *>(this)->data_;
}
void set(typename T::storage_type d) {
*static_cast<T *>(this)->data_ = d;
}
};
struct A : public impl_get_set<A> {
typedef int storage_type;
storage_type data_;
};
struct B : public impl_get_set<B> {
typedef double storage_type;
storage_type data_;
};
As this does not compile there is clearly something I have got wrong. My question is, can this be done, and if so how?
When using CRTP, you have to take care when designing the base, i.e. impl_get_set in this case. When the derived class instantiates the base specialization, e.g. as done with A: public impl_get_set<A>, the A class is still incomplete.
However the definition of impl_get_set uses typename T::storage_type in a member function declaration. This use requires a complete T. The C++03 way to solve that is to make any associated type that the CRTP base may need part of the class template parameters:
template<typename Derived, typename StorageType>
struct get_set {
typedef StorageType storage_type;
// It's possible to define those inline as before where
// Derived will be complete in the body -- which is why
// CRTP is possible at all in the first place
storage_type get() const;
void set(storage_type s);
// Convenience for clients:
protected:
typedef get_set get_set_base;
};
struct A: get_set<A, int> {
// Member type is inherited
storage_type data;
};
template<typename T>
struct B: get_set<B<T>, double> {
// Incorrect, storage_type is dependent
// storage_type data;
// First possibility, storage_type is
// still inherited although dependent
// typename B::storage_type data;
// Second possibility, convenient if
// storage_type is used multiple times
using typename B::get_set_base::storage_type;
storage_type data;
void foo(storage_type s);
};
boost::iterator_facade is a good example of a well-written C++03-style CRTP wrapper from Boost.Iterator.
C++11 gives another way to write a CRTP base thanks in part to default template arguments for function templates. By making the derived class parameter dependent again, we can use it as if it were complete -- it will only be examined when the member function template of the CRTP base specialization is instantiated, once it is complete, and not when the CRTP base specialization itself is:
// Identity metafunction that accepts any dummy additional
// parameters
template<typename T, typename... Dependent>
struct depend_on { using type = T; };
// DependOn<T, D> is the same as using T directly, except that
// it possibly is dependent on D
template<typename t, typename... D>
using DependOn = typename depend_on<T, D...>::type;
template<typename Derived>
struct get_set {
template<
// Dummy parameter to force dependent type
typename D = void
, typename Storage = typename DependOn<Derived, D>::storage_type
>
Storage get() const
{
// Nothing to change, Derived still complete here
}
};
In fact, for your example get_set arguably doesn't need to care about whether a member type is present or not:
// std::declval is from <utility>
template<
typename D = void
, typename Self = DependOn<Derived, D>
>
auto get() const
-> decltype( std::declval<Self const&>().data )
{ return static_cast<Derived const&>(*this).data; }
This implementation of get has subtly different semantics from your own in that it returns a reference to data but that's on purpose.
The best I could figure out is that you're in a chicken/egg problem.
struct A uses impl_get_set as base, that forces instantiation. But at that point A is incomplete, its contents not yet available. Therefore T::storage_type fails to resolve to anything.
The only workaround I found was to just have another template param for impl_get_set and pass it from above. So go the opposite direction:
template<typename T, typename ST>
class impl_get_set {
public:
typedef ST storage_type;
storage_type get() const {
return static_cast<const T *>(this)->data_;
}
void set(storage_type d) {
*static_cast<T *>(this)->data_ = d;
}
};
struct A : public impl_get_set<A, int> {
storage_type data_;
};
(A is currently not used in the base, I left it in for possible other plans)

How do I make a class that only compiles when its type has a certain member function?

I have a class named has_f and I want it to only accept template parameters that have a f member function. How would I do that? This is what I tried:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
But I get some cryptic errors. Here is the class I want to use:
struct A
{
void f();
};
How do I do this correctly? Thanks.
From the title of your question I presume that you don't really need a type deriving from true_type or false_type - only to prevent compilation if method f is not present. If that is the case, and if you also require a specific signature (at least in terms of arguments) for that method, in C++11 you can do something like this:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
This is for the case when f() should not accept any arguments. std::add_pointer is only needed if f returns void, because sizeof(void) is illegal.
I +1ed rapptz yesterday for
"possible duplicate of
Check if a class has a member function of a given signature"
and haven't changed my mind.
I suppose it is arguable that this question unpacks to
"A) How to check if a class has a member function of a given signature and
B) How to insist that a class template argumement is a class
as per A)". To B) in this case I would answer with static_assert, since
the questioner apparently isn't interested in enable_if alternatives.
Here is a solution that adapts my answer to
"traits for testing whether func(args) is well-formed and has required return type"
This solution assumes that has_f<T>::value should be true if and only
if exactly the public member void T::f() exists, even if T overloads f or inherits f.
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(Built with clang 3.2, gcc 4.7.2/4.8.1)
This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream) on an object to serialize it. I realized I wanted this function call to one of four things:
If object is plain old data, just write out the size and raw data
If object is a class that I've created with its own member function (object::serialize), then call that member function
If there's a template specialization for that type, use it.
If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.

template specialization for all subclasses

I would like to define a C++ template specialization that applies to all subclasses of a given base class. Is this possible?
In particular, I'd like to do this for STL's hash<>. hash<> is defined as an empty parametrized template, and a family of specializations for specific types:
template<class _Key>
struct hash { };
template<>
struct hash<char>
{
size_t
operator()(char __x) const
{ return __x; }
};
template<>
struct hash<int>
{
size_t
operator()(int __x) const
{ return __x; }
};
...
I would like to define something like this:
template<class Base>
struct hash {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
class Sub : public Base {
public:
size_t my_hash() const { ... }
};
and be able to use it like this:
hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);
However, my hash template conflicts with the generic one from STL. Is there a way (perhaps using traits) to define a template specialization that applies to all subclasses of a given base class (without modifying the STL definitions)?
Note that I know I can do this with some extra template parameters whenever this hash specialization is needed, but I'd like to avoid this if possible:
template<>
struct hash<Base> {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
....
// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
Since C++ 11 you can use SFINAE together with standard library enable_if and is_base_of to solve the problem.
C++20 makes a cleaner solution possible - basically equivalent to enable_if, which even (optionally) works with CRTP
#include <concepts>
#include <functional>
#include <unordered_set> // just for demo in main()
template <class T>
class Base {};
class Derived final : public Base<Derived> {};
template<class T>
requires std::derived_from<T, Base<T>>
struct std::hash<T> {
// constexpr is optional
constexpr size_t operator() (const T& value) const noexcept {
return 0xDEADBEEF; // FIXME: do something better :)
}
};
int main() {
// If operator() weren't constexpr, this couldn't be a *static* assert
static_assert(std::hash<Derived>()(Derived {}) == 0xDEADBEEF);
std::unordered_set<Derived> usageTest;
return 0;
}
The solution is to use SFINAE to decide whether or not to allow your specialisation depending on the class inheritance structure. In Boost you can use enable_if and is_base_of to implement this.
http://www.boost.org/doc/libs/1_47_0/libs/utility/enable_if.html
http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/boost_typetraits/reference/is_base_of.html
This was the best I could do:
template<>
struct hash<Sub> : hash<Base> {
};
I'm a little worried that I didn't have to make operator() virtual, though.
I don't think it is possible, because the way to do template specialization based on something more complex than just matching the type is C++ SFINAE, which requires second (dummy) template argument. Unfortunatelly, std::hash takes only one template argument and it is not allowed to create another version of std::hash with two template arguments. Therefore, the if you aren't satisfied with Jayen's solution, you can create your own hash type:
#include <iostream>
#include <type_traits>
using namespace std;
class ParentClass {};
class ChildClass : public ParentClass {};
// SFINAE, if T is not a child of ParentClass, substitution will fail
// You can create specializations for the general case, for another base classes, etc.
template<typename T, typename=typename enable_if<is_base_of<ParentClass, T>::value, T>::type>
struct your_hash
{
size_t operator()(const T& value)
{
return 42;
}
};
int main()
{
ParentClass pc;
ChildClass cc;
cout<<your_hash<ParentClass>()(pc)<<"\n";
cout<<your_hash<ChildClass>()(cc)<<"\n";
}