I am trying to provide an interface description for a free function listenTo(SomeAnimal) that should operate on types that fulfil particular type requirements (it should be an animal). The function arguments should not use the mechanism of interface inheritance with pure virtual methods.
I hacked a solution where the free function checks the argument type via an sfinae statement for a base class. To guarantee that the argument implements the interface of the base class I deleted the base class methods using = delete. I did not find any similar solution on the internet, thus, I am not sure if it makes sense, but it works.
Here it is, any opinions ?
#include <iostream>
#include <type_traits>
class IAnimal {
public:
// Interface that needs to be implemented
std::string sound() const = delete;
protected:
IAnimal(){}
};
class Cat : public IAnimal {
public:
// Implements deleted method
std::string sound() const {
return std::string("Meow");
}
};
class WildCat : public Cat {
public:
// Overwrites Cat sound method
std::string sound() const {
return std::string("Rarr");
}
};
class Dog : public IAnimal{
public:
// Implements deleted method
std::string sound() const {
return std::string("Wuff");
}
};
class Car {
public:
// Implements deleted method
std::string sound() const {
return std::string("Brum");
}
};
// Sfinae tests for proper inheritance
template<class TAnimal,
typename = std::enable_if_t<std::is_base_of<IAnimal, TAnimal>::value> >
void listenTo(TAnimal const & a ) {
std::cout << a.sound() << std::endl;
}
int main(){
// Objects of type IAnimal can not be instanciated
// IAnimal a;
// Cats and Dogs behave like IAnimals
Cat cat;
WildCat wildCat;
Dog dog;
Car car;
listenTo(cat);
listenTo(wildCat);
listenTo(dog);
// A car is no animal -> compile time error
// listenTo(car);
return 0;
}
C++ doesn't have yet Concepts :-( but gcc-6 implements it:
template <class T>
concept bool Animal() {
return requires(const T& a) {
{a.sound()} -> std::string;
};
}
void listenTo(const Animal& animal) {
std::cout << animal.sound() << std::endl;
}
Demo
But you can create traits relatively easily with is-detected:
typename <typename T>
using sound_type = decltype(std::declval<const T&>().sound());
template <typename T>
using has_sound = is_detected<sound_type, T>;
template <typename T>
using is_animal = has_sound<T>;
// or std::conditional_t<has_sound<T>::value /*&& other_conditions*/,
// std::true_type, std::false_type>;
And then regular SFINAE:
template<class T>
std::enable_if_t<is_animal<T>::value>
listenTo(const T& animal) {
std::cout << animal.sound() << std::endl;
}
Another way, avoiding the complication of inheritance, is to create a type trait:
#include <iostream>
#include <type_traits>
template<class T>
struct is_animal : std::false_type {};
class Cat {
public:
std::string sound() const {
return std::string("Meow");
}
};
template<> struct is_animal<Cat> : std::true_type {};
class WildCat : public Cat {
public:
// Overwrites Cat sound method
std::string sound() const {
return std::string("Rarr");
}
};
template<> struct is_animal<WildCat> : std::true_type {};
class Dog {
public:
std::string sound() const {
return std::string("Wuff");
}
};
template<> struct is_animal<Dog> : std::true_type {};
class Car {
public:
std::string sound() const {
return std::string("Brum");
}
};
// Sfinae tests for proper inheritance
template<class TAnimal,
typename = std::enable_if_t<is_animal<TAnimal>::value> >
void listenTo(TAnimal const & a ) {
std::cout << a.sound() << std::endl;
}
int main(){
// Objects of type IAnimal can not be instanciated
// IAnimal a;
// Cats and Dogs behave like IAnimals
Cat cat;
WildCat wildCat;
Dog dog;
Car car;
listenTo(cat);
listenTo(wildCat);
listenTo(dog);
// A car is no animal -> compile time error
// listenTo(car);
return 0;
}
namespace details {
template<template<class...>class Z, class always_void, 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 is a meta type trait that helps write other type traits.
template<class T>
using sound_result = decltype( std::declval<T>().sound() );
sound_result<T> is the result of t.sound() where t is of type T.
template<class T>
using can_sound = can_apply<sound_result, T>;
can_sound<T> is a true type if and only if t.sound() is valid to call.
We can now say that animals are things that can sound.
template<bool b>
using bool_t = std::integral_constant<bool, b>;
template<class T>
using is_animal = bool_t< can_sound<T>{} >; // add more requirements
template<class TAnimal,
std::enable_if_t< is_animal<TAnimal const&>{}, int> =0
>
void listenTo(TAnimal const & a ) {
std::cout << a.sound() << std::endl;
}
We get an error saying there is no matching overload if we try to listenTo(0) or somesuch.
Requiring that .sound() return something streamable can be written as well.
template<class T>
using stream_result = decltype( std::declval<std::ostream&>() << std::declval<T>() );
template<class T>
using can_stream = can_apply< stream_result, T >;
template<class T>
using stream_sound_result = stream_result< sound_result< T > >;
template<class T>
using can_stream_sound = can_apply< stream_sound_result, T >;
Now we can upgrade our animal test:
template<class T>
using is_animal = bool_t< can_stream_sound<T>{} >;
You didn't ask for an alternative solution. Instead, you asked for an opinion about your solution.
Well, here is my opinion, hoping it can help you.
That's a weak sfinae expression. You can easily break it using:
listenTo<Car, void>(car);
At least, I'd suggest you to rewrite your function as it follows:
template<class TAnimal>
std::enable_if_t<std::is_base_of<IAnimal, TAnimal>::value>
listenTo(TAnimal const & a ) {
std::cout << a.sound() << std::endl;
}
That said, as it stands, you don't really need to use neither std::enable_if_t nor any other sfinae expression.
In this case, a static_assert is more than enough:
template<class TAnimal>
void listenTo(TAnimal const & a ) {
static_assert(std::is_base_of<IAnimal, TAnimal>::value, "!");
std::cout << a.sound() << std::endl;
}
This way you can also remove the useless definition of sound from IAnimal and still you'll have a nice compilation error.
Now, if you want to drop also the IAnimal interface, a possible solution (that hasn't been mentioned by other answer) follows:
#include <iostream>
#include <type_traits>
template<typename> struct tag {};
template<typename... T> struct check;
template<typename T, typename... U>
struct check<T, U...>: check<U...> {
using check<U...>::verify;
static constexpr bool verify(tag<T>) { return true; }
};
template<>
struct check<> {
template<typename T>
static constexpr bool verify(tag<T>) { return false; }
};
class Cat {
public:
std::string sound() const { return std::string("Meow"); }
};
class WildCat {
public:
std::string sound() const { return std::string("Rarr"); }
};
class Dog {
public:
std::string sound() const { return std::string("Wuff"); }
};
class Car {
public:
std::string sound() const { return std::string("Brum"); }
};
using AnimalCheck = check<Cat, WildCat, Dog>;
template<class TAnimal>
void listenTo(TAnimal const & a ) {
static_assert(AnimalCheck::verify(tag<TAnimal>{}), "!");
std::cout << a.sound() << std::endl;
}
int main(){
Cat cat;
WildCat wildCat;
Dog dog;
Car car;
listenTo(cat);
listenTo(wildCat);
listenTo(dog);
// A car is no animal -> compile time error
//listenTo(car);
return 0;
}
As requested in the comments, you can centralize the check of the existence of the method to be called in the check class.
As an example:
template<typename T, typename... U>
struct check<T, U...>: check<U...> {
static constexpr auto test()
-> decltype(std::declval<T>().sound(), bool{})
{ return true; }
static_assert(test(), "!");
using check<U...>::verify;
static constexpr bool verify(tag<T>) { return true; }
};
Or a more compact version:
template<typename T, typename... U>
struct check<T, U...>: check<U...> {
static_assert(decltype(std::declval<T>().sound(), std::true_type{}){}, "!");
using check<U...>::verify;
static constexpr bool verify(tag<T>) { return true; }
};
This is somehow a way of checking for a concept by using only features from the current revision of the language.
Note that concepts would have helped to do the same somehow and somewhere in the code, but they are not part of the standard yet.
deleteing a function removes it, it doesn't introduce a dependency on it. It says "this class does not have this function". So as far as implementing/annotating an interface goes, it's a bizarre way to achieve the goal. It's a bit like building a full-cockpit F-32 simulator and telling a very confused first test pilot "well we removed all the buttons so you'll know what actually exists in a real plane".
The way interfaces are implemented in C++ is with virtual functions, and you annotate a virtual function as being "pure" (to be implemented) by giving them a body of "0", like this:
struct IFace {
virtual void sound() = 0;
};
This makes it impossible to create a concrete instance of IFace or any class that derives from it, until you reach a part of the hierarchy where sound() is implemented:
struct IAudible {
virtual void sound() const = 0;
};
struct Explosion : public IAudible {
// note the 'override' keyword, optional but helpful
virtual void sound() const override { std::cout << "Boom\n"; }
};
struct Word : public IAudible {
};
void announce(const IAudible& audible) {
audible.sound();
}
int main() {
Explosion e;
announce(e);
}
Demo here: http://ideone.com/mGnw6o
But if we try to instantiate "Word", we get a compiler error: http://ideone.com/jriyay
prog.cpp: In function 'int main()':
prog.cpp:21:14: error: cannot declare variable 'w' to be of abstract type 'Word'
Word w;
prog.cpp:11:12: note: because the following virtual functions are pure within 'Word':
struct Word : public IAudible {
^
prog.cpp:4:22: note: virtual void IAudible::sound() const
virtual void sound() const = 0;
Related
Consider this case with multiple (implementation) inheritance with mixin pattern:
#include <string>
#include <iostream>
template <typename... Bases>
struct Overloads : public Bases... {};
struct Human {};
struct Animal {};
struct Named {
std::string name_;
void setName(const std::string& name) {
name_ = name;
}
const std::string& getName() const noexcept { return name_; }
};
template <typename OverloadsType>
struct Actor : public OverloadsType {
Actor() : OverloadsType() {}
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) {
// ???????
this->setName(other_actor.getName());
}
};
int main() {
Actor<Overloads<Human, Named>> named_human;
named_human.setName("Bob");
std::cout << named_human.getName() << '\n';
Actor<Overloads<Animal, Named>> named_animal;
Actor<Overloads<Animal, Named>> animal_once_a_human (named_human);
std::cout << animal_once_a_human.getName() << '\n';
}
The code works correctly, printing two Bobs: Link
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
Here's a basic blueprint. This can be further refined so that the concept actually checks that getName() return a std::string.
#include <string>
#include <iostream>
template<typename T>
concept has_a_name = requires(T &t) {
{ t.getName() };
};
template<typename T, typename U>
void give_name(const T &t, U &u)
{
}
template<has_a_name T, typename U>
void give_name(const T &t, U &u)
{
u.setName(t.getName());
}
struct tom {
std::string getName() const
{
return "Tom";
}
};
struct jerry {};
struct cartoon {
void setName(const std::string &s)
{
std::cout << s << "\n";
}
template<typename T>
cartoon(const T &t)
{
give_name(t, *this);
}
};
int main()
{
tom Tom;
jerry Jerry;
cartoon mgm{Tom}, mgm2{Jerry};
return 0;
}
As far as generalizing this goes, any possible "generic" way of defining getters and setters will either be even longer than this, or use arcane, cryptic, difficult to read templates that end up expressing very simple operations.
A simple concept that defines each class that implements a particular getter, and a pair of template functions that select a stub or the real deal, via simple overload resolution, is easy to read, understand and follow.
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
So, if the source also has the base class, it should be copied, and otherwise we should use a default constructed instance. This is straightforward.
We can define a function to extract that initializer, a copy of a base if there is one, otherwise a default constructed instance:
template <std::semiregular T, typename U>
constexpr auto extract(const U& u) -> T {
if constexpr (std::derived_from<U, T>) {
return u;
}
else {
return T();
}
}
Then we can use that to initialize the "overloads":
template <typename... Bases>
struct Overloads : public Bases... {
Overloads() = default;
template <typename OtherOverloads>
Overloads(const OtherOverloads& other_overloads) : Bases{extract<Bases>(other_overloads)}... {}
};
Then we can use that logic to initialize the actor:
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) : OverloadsType(other_actor) {}
See https://godbolt.org/z/ofjPb8x75
Let's consider a CRTP template class Print which is meant to print the derived class:
template <typename T>
struct Print {
auto print() const -> void;
auto self() const -> T const & {
return static_cast<T const &>(*this);
}
private:
Print() {}
~Print() {}
friend T;
};
Because I want to specialize print based on the derived class like we could do this with an override, I don't implement the method yet.
We can wrap an Integer and do so for example:
class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}
private:
int m_i;
friend Print<Integer>;
};
template <>
auto Print<Integer>::print() const -> void {
std::cout << self().m_i << std::endl;
}
This works so far, now let's say I want to Print a generic version of a wrapper:
template <typename T>
class Wrapper :
public Print<Wrapper<T>>
{
public:
Wrapper(T value) : m_value(std::move(value)) {}
private:
T m_value;
friend Print<Wrapper<T>>;
};
If I specialize my print method with a specialization of the Wrapper it compile and works:
template <>
auto Print<Wrapper<int>>::print() const -> void
{
cout << self().m_value << endl;
}
But if I want to say "for all specializations of Wrapper, do that", it doesn't work:
template <typename T>
auto Print<Wrapper<T>>::print() const -> void
{
cout << self().m_value << endl;
}
If I run this over the following main function:
auto main(int, char**) -> int {
auto i = Integer{5};
i.print();
auto wrapper = Wrapper<int>{5};
wrapper.print();
return 0;
}
The compiler print:
50:42: error: invalid use of incomplete type 'struct Print<Wrapper<T> >'
6:8: error: declaration of 'struct Print<Wrapper<T> >'
Why ? How can I do that ? Is it even possible or do I have to make a complete specialization of my CRTP class ?
You can do this in a bit of a roundabout way so long as you're careful.
Live Demo
Your Print class will rely on yet another class PrintImpl to do the printing.
#include <type_traits>
template<class...>
struct always_false : std::false_type{};
template<class T>
struct PrintImpl
{
void operator()(const T&) const
{
static_assert(always_false<T>::value, "PrintImpl hasn't been specialized for T");
}
};
You'll partially specialize this PrintImpl for your Wrapper class:
template<class T>
struct PrintImpl<Wrapper<T>>
{
void operator()(const Wrapper<T>& _val) const
{
std::cout << _val.m_value;
}
};
And make sure that Wrapper declares this PrintImpl to be a friend:
friend struct PrintImpl<Wrapper<T>>;
The Print class creates an instance of PrintImpl and calls operator():
void print() const
{
PrintImpl<T>{}(self());
}
This works so long as your specializations are declared before you actually instantiate an instance of the Print class.
You can also fully specialize PrintImpl<T>::operator() for your Integer class without writing a class specialization:
class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}
private:
int m_i;
friend PrintImpl<Integer>;
};
template <>
void PrintImpl<Integer>::operator()(const Integer& wrapper) const {
std::cout << wrapper.m_i << std::endl;
}
To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.
Is there an alternative to using dynamic_cast in C++?
For example, in the code below, I want to be able to have Cat objects purr. But only Cat objects and not Dog objects. I know this goes against deriving the class from Mammal since it's not very polymorphic, but I still want to know if I can do this without dynamic_cast.
My class declarations
class Mammal
{
public:
virtual void Speak() const {cout << "Mammals yay!\n";}
};
class Cat: public Mammal
{
public:
void Speak() const{cout << "Meow\n";}
void Purr() const {cout <"rrrrrrrr\n";}
};
class Dog: public Mammal
{
public:
void Speak() const{cout << "Woof!\n";}
};
In Main
int main()
{
Mammal *pMammal;
pMammal = new Cat;
pMammal->Purr(); //How would I call this without having to use dynamic_cast?
return 0;
}
If you know there is a fixed set of implementations, you can create virtual functions that do the casting for you. This can ne cheaper than dynamic_cast.
So:
struct Cat;
struct Mammal {
virtual Cat* AsCat(){ return nullptr; }
};
struct Cat : Mammal {
virtual Cat* AsCat() { return this; }
};
I have done this with template tomfoolery in C++11 so you can even make it look like a cast.
#include <utility>
#include <iostream>
template<typename T>
struct fast_castable_leaf {
virtual T* do_fast_cast(T* unused=nullptr) { return nullptr; }
virtual T const* do_fast_cast(T* unused=nullptr) const { return nullptr; }
virtual ~fast_castable_leaf() {}
};
template<typename Tuple>
struct fast_castable;
template<template<typename...>class Tuple>
struct fast_castable<Tuple<>> {
virtual ~fast_castable() {}
};
template<template<typename...>class Tuple, typename T, typename... Ts>
struct fast_castable<Tuple<T,Ts...>>:
fast_castable_leaf<T>,
fast_castable<Tuple<Ts...>>
{};
template<typename T> struct block_deduction { typedef T type; };
template<typename T> using NoDeduction = typename block_deduction<T>::type;
template<typename T>
T* fast_cast( NoDeduction<fast_castable_leaf<T>>* src ) {
return src->do_fast_cast();
}
template<typename T>
T const* fast_cast( NoDeduction<fast_castable_leaf<T>> const* src ) {
return src->do_fast_cast();
}
template<typename T, typename D>
struct fast_cast_allowed : std::integral_constant<bool,
std::is_base_of<T,D>::value || std::is_same<T,D>::value
> {};
template<typename D, typename B, typename Tuple>
struct implement_fast_cast;
template<typename D, typename B, template<typename...>class Tuple>
struct implement_fast_cast<D,B,Tuple<>> : B {};
template<typename D, typename B, template<typename...>class Tuple, typename T, typename... Ts>
struct implement_fast_cast<D,B,Tuple<T,Ts...>> : implement_fast_cast<D, B, Tuple<Ts...>> {
private:
D* do_cast_work(std::true_type) { return static_cast<D*>(this); }
D const* do_cast_work(std::true_type) const { return static_cast<D const*>(this); }
std::nullptr_t do_cast_work(std::false_type) { return nullptr; }
std::nullptr_t do_cast_work(std::false_type) const { return nullptr; }
public:
T* do_fast_cast( T* unused = nullptr ) override { return do_cast_work( fast_cast_allowed<T,D>() ); }
T const* do_fast_cast( T* unused = nullptr ) const override { return do_cast_work( fast_cast_allowed<T,D>() ); }
};
And an example of the above framework in use:
struct Dog;
struct Cat;
struct Moose;
template<typename...>struct Types {};
typedef Types<Dog, Cat, Moose> Mammal_Types;
// A Mammal can be fast-casted to any of the Mammal_Types:
struct Mammal : fast_castable<Mammal_Types>
{};
// Cat wants to implement any legal fast_casts it can for Mammal in the
// set of Mammal_Types. You can save on overhead by doing Types<Cat> instead
// of Mammal_Types, but this is less error prone:
struct Cat : implement_fast_cast< Cat, Mammal, Mammal_Types >
{};
int main() {
Cat c;
Mammal* m=&c;
// so m is a pointer to a cat, but looks like a mammal. We use
// fast cast in order to turn it back into a Cat:
Cat* c2 = fast_cast<Cat>(m);
// and we test that it fails when we try to turn it into a Dog:
Dog* d2 = fast_cast<Dog>(m);
// This prints out a pointer value for c2, and 0 for d2:
std::cout << c2 << "," << d2 << "\n";
}
Live Example
This can be cleaned up to support a more standard fast_cast<Cat*> instead of a fast_cast<Cat>, as well as fast_cast<Cat&>, then blocking direct access to do_fast_cast by making it private and fast_cast a friend, and allowing for some means to have virtual inheritance in the case that you need it.
But the core of the system is above. You get cast-to-derived at the cost of a single virtual function lookup without having to maintain much of the machinery yourself.
Alternative implementation:
template<class...>struct types{using type=types;};
template<typename T>
struct fast_castable_leaf {
virtual T* do_fast_cast(T* unused=nullptr) { return nullptr; }
virtual T const* do_fast_cast(T* unused=nullptr) const { return nullptr; }
virtual ~fast_castable_leaf() {}
};
template<class Tuple>
struct fast_castable;
template<>
struct fast_castable<types<>> {
virtual ~fast_castable() {}
};
template<class T0, class...Ts>
struct fast_castable<types<T0, Ts...>>:
fast_castable_leaf<T0>,
fast_castable<types<Ts...>>
{};
template<class T> struct block_deduction { typedef T type; };
template<class T> using NoDeduction = typename block_deduction<T>::type;
template<class T>
T* fast_cast( NoDeduction<fast_castable_leaf<T>>* src ) {
return src->do_fast_cast();
}
template<class T>
T const* fast_cast( NoDeduction<fast_castable_leaf<T>> const* src ) {
return src->do_fast_cast();
}
template<class T, class D>
struct fast_cast_allowed : std::integral_constant<bool,
std::is_base_of<T,D>::value || std::is_same<T,D>::value
> {};
template<class Self, class Base, class Types>
struct implement_fast_cast;
template<class Self, class Base>
struct implement_fast_cast<Self,Base,types<>> : Base {
private:
template<class, class, class>
friend struct implement_fast_cast;
Self* do_cast_work(std::true_type) { return static_cast<Self*>(this); }
Self const* do_cast_work(std::true_type) const { return static_cast<Self const*>(this); }
std::nullptr_t do_cast_work(std::false_type) { return nullptr; }
std::nullptr_t do_cast_work(std::false_type) const { return nullptr; }
};
template<class Self, class Base, class T0, class... Ts>
struct implement_fast_cast<Self,Base,types<T0,Ts...>> :
implement_fast_cast<Self, Base, types<Ts...>>
{
public:
T0* do_fast_cast( T0* unused = nullptr ) override { return this->do_cast_work( fast_cast_allowed<T0,Self>() ); }
T0 const* do_fast_cast( T0* unused = nullptr ) const override { return this->do_cast_work( fast_cast_allowed<T0,Self>() ); }
};
struct Dog;
struct Cat;
struct Moose;
typedef types<Dog, Cat, Moose> Mammal_Types;
struct Mammal : fast_castable<Mammal_Types>
{};
struct Cat : implement_fast_cast< Cat, Mammal, Mammal_Types >
{};
int main() {
Cat c;
Mammal* m=&c;
Cat* c2 = fast_cast<Cat>(m);
Dog* d2 = fast_cast<Dog>(m);
std::cout << c2 << "," << d2 << "\n";
}
which might be easier for some compilers to swallow. Live example.
Note that for a long list of types, the above gets unwieldy (at both compile, and possibly run time), because it relies on linear inheritance.
A binary inheritance system would be a bit more complex to program, but would get rid of that problem. In it, you'd split your list of things to inherit from into two lists of equal size and inherit from both. The implement fast cast would have to inherit from Base via a virtual intermediary.
C++ doesn't support sending messages as, e.g., Objective C or Smalltalk do. To call a method you need to have a statically typed handle for an object supporting the method. Whether you need to use a dynamic_cast<Cat*>(pointer) or if you can get away with something else, e.g., a static_cast<Cat*>(pointer) is a separate question.
Since dynamic_cast<...>() is relatively expensive and trying a potentially unbounded number of different classes isn't feasible, it may be preferable to use a visit() method in the base class which is called with a visitor. However, these are just techniques to get hold of a properly typed reference.
You're dealing with a pointer to type Mammal and presumably Mammal does not define Purr(). You absolutely must cast it to a pointer to type Cat in order to access Purr(). You can do this with a C-style cast or a dynamic_cast, and the latter is generally the more proper thing to do in C++. dynamic_cast also has the advantage that you can use it to test, at runtime, whether your Mammal object is a Cat or not, so you can decide whether you can call Purr().
Three variants:
dynamic_cast, which you supposedly already aware of.
static_cast, which is compile-time cast, i.e. a) types are checked for compatibility b) offset between base class and derived class is calculated and taken into account c) there's no runtime check.
reinterpret_cast, which is also compile-time cast, done without any type check and without offset calculation. Use with caution - this cast might cause bugs very difficult to debug.
For complete reference and examples of these casts, look for some books and tutorials, for example: http://www.cplusplus.com/doc/tutorial/typecasting/
Why won't the compiler select the Interface template when running the following code? Are additional declarations / hints needed or won't this work in general?
I'm just curious if this is actually possible.
class Interface {
public :
virtual void Method() = 0;
virtual ~Interface() { }
};
class Derived : Interface {
public :
void Method() {
cout<<"Interface method"<<endl;
}
};
template<typename T>
struct Selector {
static void Select(T& o) {
cout<<"Generic method"<<endl;
}
};
template<>
struct Selector<Interface> {
static void Select(Interface& o) {
o.Method();
}
};
int i;
Selector<int>::Select(i) // prints out "Generic method" -> ok
Derived d;
Selector<Derived>::Select(d); // prints out "Generic method" -> wrong
// should be "Interface method"
Try this (and #include <type_traits>):
template <typename T, typename = void>
struct Selector
{
static void Select(T & o)
{
std::cout << "Generic method" << std::endl;
}
};
template <typename T>
struct Selector<T,
typename std::enable_if<std::is_base_of<Interface, T>::value>::type>
{
static void Select(Interface & o)
{
o.Method();
}
};
It turns out that enable_if combined with defaulted template arguments can be used to guide partial specialisations.
The compiler will select the version of a function that is the closest match. A function that takes the exact type for a parameter always wins over one that requires a conversion. In this case the template function is an exact match, since it matches anything; the Interface specialization would require the conversion of the parameter from a Derived to an Interface.
This will allow you to achieve the desired result:
#include <iostream>
#include <type_traits>
using namespace std;
class Interface {
public :
virtual void Method() = 0;
virtual ~Interface() { }
};
class Derived : public Interface {
public :
void Method() {
cout<<"Interface method"<<endl;
}
};
template<typename T, typename S = void>
struct Selector {
static void Select(T& o) {
cout<<"Generic method"<<endl;
}
};
template<typename T>
struct Selector<T, typename enable_if< is_base_of<Interface, T>::value >::type> {
static void Select(Interface& o) {
o.Method();
}
};
int main()
{
int i;
Selector<int>::Select(i); // prints out "Generic method" -> ok
Derived d;
Selector<Derived>::Select(d); // prints out "Generic method" -> wrong
// should be "Interface method"
}