I was wondering how we can declare an interface in C++ without using virtual functions. After some internet searching I put together this solution:
#include <type_traits>
using namespace std;
// Definition of a type trait to check if a class defines a member function "bool foo(bool)"
template<typename T, typename = void>
struct has_foo : false_type { };
template<typename T>
struct has_foo<T, typename enable_if<is_same<bool, decltype(std::declval<T>().foo(bool()))>::value, void>::type> : true_type { };
// Definition of a type trait to check if a class defines a member function "void bar()"
template<typename T, typename = void>
struct has_bar : false_type { };
template<typename T>
struct has_bar<T, typename enable_if<is_same<void, decltype(std::declval<T>().bar())>::value, void>::type> : true_type { };
// Class defining the interface
template <typename T>
class Interface{
public:
Interface(){
static_assert(has_foo<T>::value == true, "member function foo not implemented");
static_assert(has_bar<T>::value == true, "member function bar not implemented");
}
};
// Interface implementation
class Implementation:Interface<Implementation>{
public:
// If the following member functions are not declared a compilation error is returned by the compiler
bool foo(bool in){return !in;}
void bar(){}
};
int main(){}
I'm planning to use this design strategy in a project where I will use static polymorphism only. The C++ standard I will use in the project is C++11.
What do you think are the pros and cons of this approach?
What improvements can be made on the code I proposed?
EDIT 1: I just realised that inheriting from Interface is not needed. This code could also be used:
class Implementation{
Interface<Implementation> unused;
public:
bool foo(bool in){return !in;}
void bar(){}
};
EDIT 2-3: One major difference between the static_assert solution (with or without CRTP) and the standard CRTP is that the CRTP does not guarantee that the derived class implements all the interface members. E.g., the following code compiles correctly:
#include <type_traits>
using namespace std;
template< typename T>
class Interface{
public:
bool foo(bool in){
return static_cast<T*>(this)->foo(in);
}
void bar(){
static_cast<T*>(this)->bar();
}
};
class Implementation: public Interface<Implementation>{
public:
// bool foo(bool in){return !in;}
// void bar(){}
};
int main(){}
An error about a missing member function will be returned by the compiler only when the functions foo or bar will be required.
The way I see it, the static_assert solution feels more like an interface declaration than CRTP alone.
It appears that you want to implement concepts (lite). You may want to read the article before attempting an implementation.
Absent compiler support, you can partially implement this idea. Your
static_assert
idea is a known way to express interface requirements.Consider the
Sortable
example from the link. You can create a class templateSortable
, usestatic_assert
to assert all kind of thinks about the template parameter. You explain to your users that they need to implement a certain cet of methods, and to enforce that set is implemented, they need to make use ofSortable<TheirClass>
one way or another.In order to express, right in a function declaration. the idea that your function requires a
Sortable
, you will have to resort to something like this: