C++ template specialization for interface - c++

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"
}

Related

derived class as a parameter of templated function which is specialized for its base class

class Base {};
class Derived : public Base {};
class SomeClass
{
template<typename T>
static void SetContent(T* pChild, OVariant content)
{
LOG_ASSERT(0, "All classes must be specialized!. Please provide implementation for this class.");
}
};
template <>
void SomeClass::SetContent(Base* value)
{
LOG_TRACE("Yay!");
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?
You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base
#include <type_traits>
#include <iostream>
class Base {};
class Derived : public Base {};
template <typename T,typename = void>
struct impl {
void operator()(T*) {
std::cout <<"All classes must be specialized!. Please provide implementation for this class.\n";
}
};
template <typename T>
struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
void operator()(T*) {
std::cout << "Yay\n";
}
};
class SomeClass
{
public:
template<typename T>
static void SetContent(T* pChild)
{
impl<T>{}(pChild);
}
};
struct bar{};
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);
bar b;
foo.SetContent(&b);
}
Output:
Yay
All classes must be specialized!. Please provide implementation for this class.
//want it to call SomeClass::SetContent(Base* value)
Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).
A workaround would be to have all SetContent's explicit specializations to form an overload set. You will have to do it yourself:
#include <iostream>
#include <utility>
#include <functional>
class Base {};
class Derived : public Base {};
template <class... T>
struct Overloads : T... {
Overloads(const T &... t) : T(t)... {}
using T::operator()...;
};
template <class R, class... Args>
struct FunctionP {
using F = R(Args...);
FunctionP(F *t) : t_(t) {}
R operator()(Args... args) const {
return std::invoke(t_, std::forward<Args>(args)...);
}
F *t_;
};
struct SomeClass {
template<typename T>
static void SetContent(T *x) {
Overloads o(FunctionP(&SetContentImpl<Base>)); // enumerates all the specializations here
if constexpr (std::is_invocable_v<decltype(o), T *>) {
o(x);
} else {
SetContentImpl(x);
}
}
template<typename T>
static void SetContentImpl(T *) {
std::cout << "1";
}
};
template <>
void SomeClass::SetContentImpl(Base *) {
std::cout << "2";
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
godbolt

Multiple inheritance with templated template

I want to do multiple inheritance via template arguments and pass reference to this in each base class, so I can call top level object's method from each base class's method. I can do it with manual inheritance, but I want to be able to do this via templates arguments.
Godbolt link
Godbolt link with manual inheritance
#include <cstdio>
template <typename T>
struct Foo {
Foo(T &t)
: t_(t) {
}
void foo() {
t_.call("foo");
}
T &t_;
};
template <typename T>
struct Bar {
Bar(T &t)
: t_(t) {
}
void bar() {
t_.call("bar");
}
T &t_;
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl>... {
Impl()
: Methods<Impl>(*this)... {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
I tried this approach, but it gives
type/value mismatch at argument 1 in template parameter list for 'template<class> class ... Methods'
Thanks to #Nicol Bolas, he advised to use static_cast and CRTP for this
#include <cstdio>
template <typename T>
struct Foo {
void foo() {
static_cast<T*>(this)->call("foo");
}
};
template <typename T>
struct Bar {
void bar() {
static_cast<T*>(this)->call("bar");
}
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl<Methods...>>... {
Impl() {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}

CRTP applied on a template class

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;
}

Using = delete for interface description

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;

'using' declaration as SFINAE

Could I use SFINAE (or another technique) for using declaration while private deriving from template class?
For better understanding see code below:
#include <iostream>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
template <class T>
struct D : private T {
using T::f;
// using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // fail. But wants to be ok and prints 'S2::g'
return 0;
}
How can I reach desired behaviour (if it possible)?
A variant of Bryan Chen's answer that looks uglier, but makes it easier to extend to multiple checks, and doesn't require duplicating the code that's shared between D<type-with-f> and D<type-without-f>, is to use an inheritance chain, where each step checks one additional member. The only duplication required is the inheritance of constructors, if appropriate.
struct A {
void f() { }
void g() { }
void i() { }
};
// The generic case. D<T, char[N]> simply provides what D<T, char[N+1]> provides.
template <typename T, typename U = char[1]>
struct D : D<T, char[sizeof(U) + 1]> {
using D<T, char[sizeof(U) + 1]>::D;
};
// The end of the chain. This is where T gets inherited. It declares all of its own
// specialisations as its friends, so that they can access other members of T.
template <typename T>
struct D<T, char[6]> : private T {
template <typename, typename>
friend struct D;
D(int) { }
void fun() { }
};
// Check for T::f.
template <typename T>
struct D<T, char[2 + !sizeof(&T::f)]> : D<T, char[3]> {
using D<T, char[3]>::D;
using T::f;
};
// Check for T::g.
template <typename T>
struct D<T, char[3 + !sizeof(&T::g)]> : D<T, char[4]> {
using D<T, char[4]>::D;
using T::g;
};
// Check for T::h.
template <typename T>
struct D<T, char[4 + !sizeof(&T::h)]> : D<T, char[5]> {
using D<T, char[5]>::D;
using T::h;
};
// Check for T::i.
template <typename T>
struct D<T, char[5 + !sizeof(&T::i)]> : D<T, char[6]> {
using D<T, char[6]>::D;
using T::i;
};
int main() {
D<A> d = 4; // ok: verify that constructors got inherited
// A &a = d; // error: verify that inheritance of A is private
d.f(); // ok: verify that f got inherited
d.g(); // ok: verify that g got inherited
// d.h(); // error: verify that h is not available
d.i(); // ok: verify that i got inherited
d.fun(); // ok: verify that the inheritance chain didn't get broken
}
Note: instead of checking &T::f, you may want to do something with std::declval<T>().f() instead. The former cannot handle overloaded functions.
C++ partial template specialization and use decltype(void(&T::g)) for SFINAE
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
template <class T, class V = void>
struct D : private T {
using T::f;
};
template <class T>
struct D<T, decltype(void(&T::g))> : private T {
using T::f;
using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // ok. Prints 'S2::g'
return 0;
}
Live Demo
Edit:
This is another approach that is more flexible, but I have no idea how does private virtual inheritance works with real use cases. Please let me know if it may cause any issue (e.g. UB).
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::f\n"; }
};
struct S2 {
void f() { std::cout << "S2::f\n"; }
void g() { std::cout << "S2::g\n"; }
};
struct S3 {
void g() { std::cout << "S3::g\n"; }
};
template <class T, class = void>
struct D_f {};
template <class T>
struct D_f<T, decltype(void(&T::f))> : private virtual T {
using T::f;
};
template <class T, class = void>
struct D_g {};
template <class T>
struct D_g<T, decltype(void(&T::g))> : private virtual T {
using T::g;
};
template <class T>
struct D : D_f<T>, D_g<T> {
};
int main() {
D<S1>().f();
D<S2>().f();
D<S2>().g();
D<S3>().g();
return 0;
}
Live Demo