c++ template specialization for base class - c++

I would like to have a special formatter for BASECLASS and all derived classes. I have the following classes:
struct BASECLASS { ... };
struct SPECIALFORMAT : BASECLASS { ... }
struct ANOTHERSPECIALFORMAT : BASECLASS { ... }
template <class T>
struct LISTFORMATTER {
list<T> l;
bool format() {
};
}
bool LISTFORMATTER<BASECLASS>::format() { ... }
LISTFORMATTER<BASECLASS> bcFt;
LISTFORMATTER<SPECIALFORMAT> spFt;
LISTFORMATTER<ANOTHERSPECIALFORMAT> aspFt;
bcFt.format(); // <-- ok
spFt.format(); // <-- Calling standard format(), not specialized
aspFt.format(); // <-- Calling standard format(), not specialized
How can I specialize a method for a base class and all inherited classes?
EDIT preferible not using boost. c++ (not c++11)

First, you need is_base_of. If you don't want to use Boost or C++11, then grab one here:
How does `is_base_of` work?
Then, you can do this:
template <bool B> struct bool_ {};
// ...
bool format() { do_format(bool_<is_base_of<BASECLASS, T>::value>()); }
bool do_format(bool_<false>) {
// not inheriting BASECLASS
}
bool do_format(bool_<true>) {
// inheriting BASECLASS
}
BTW, there is, AFAIK, no way of doing this non-intrusively, i.e. simply by adding a specialization.
Edit: Actually, you can probably do it without is_base_of:
// ...
bool format() { do_format((T*)0); }
bool do_format(void*) { /* not inheriting */ }
bool do_format(BASECLASS*) { /* inheriting */ }
This works because derived->base is a better conversion than class->void.

I think you could do this with enable_if and is_base_of (either from c++11 or boost).

Tag dispatching may help:
struct BASECLASS { };
struct SPECIALFORMAT : BASECLASS { };
struct ANOTHERSPECIALFORMAT : BASECLASS { };
template <typename T>
struct IsDerivedFromBASECLASS {
static const bool value = false; //std::is_base_of<BASECLASS, T>::value;
};
template <>
struct IsDerivedFromBASECLASS<BASECLASS> { static const bool value = true; };
template <>
struct IsDerivedFromBASECLASS<SPECIALFORMAT> { static const bool value = true; };
template <>
struct IsDerivedFromBASECLASS<ANOTHERSPECIALFORMAT> { static const bool value = true; };
template <class T>
struct LISTFORMATTER {
//list<T> l;
bool format();
};
template <typename T, bool IsABASECLASS>
struct helper_format {
bool operator() (LISTFORMATTER<T>&)
{
// default implementation
return true;
}
};
template <typename T>
struct helper_format<T, false>
{
bool operator() (LISTFORMATTER<T>&)
{
// specialization implementation
return false;
}
};
template<typename T>
bool LISTFORMATTER<T>::format() {
return helper_format<T, IsDerivedFromBASECLASS<T>::value>(*this);
}

Related

Idiomatic C++11 for delegating template specialisations to a default implementation

I'm making a struct Box<T> that handles some data. The specifics are unimportant.
An important note however is that Box<T> can store a pointer, but it might not. So both Box<int> and Box<int *> are valid. Obviously, if we own Box.data, we're going to need to delete data if it is a pointer type.
Here's a solution I came up with that works in C++11:
template <typename T> struct BoxTraits;
template <typename T> struct Box {
using traits_t = BoxTraits<T>;
T data;
~Box() = default; // not required, I know
T get_data() { return traits_t::get_data(this); }
};
template <typename T> struct Box<T *> {
using traits_t = BoxTraits<T *>;
T *data;
~Box() { delete data; }
T *get_data() { return traits_t::get_data(this); }
};
template <typename T> struct BoxTraits {
static T get_data(Box<T> *const box) { return box->data; }
};
Box::get_data is here to illustrate an issue with this design pattern. For every single method I want to add to Box, I need to add some boiler plate in each specialisation. Note that I would also need a Box<T *const> specialisation.
This seems like quite a rubbish solution. In C++14, I could use if constexpr with a is_ptr<T> trait and only have to write extra code in the methods that need specialising... Is there any way I can do this is in C++11?
This solution is shorter, cleaner and works for Box<U *const>!
template <typename T> struct is_ptr { static const bool value = false; };
template <typename U> struct is_ptr<U *> { static const bool value = true; };
template <typename U> struct is_ptr<U *const> {
static const bool value = true;
};
template <typename T> struct Box {
T data;
~Box() {
if constexpr (is_ptr<T>::value) {
delete data;
}
}
T get_data() { return data; }
};
First off, C++11 already has std::is_pointer, no need to roll your own. You can see that it inherits from std::true_type or std::false_type instead of defining its own value member. The reason for that is tag dispatching, that can effectively replace if constexpr in this situation:
template <typename T> struct Box {
T data;
~Box() {
destroy(std::is_pointer<T>{});
}
private:
void destroy(std::true_type) {
delete data;
}
void destroy(std::false_type) {} // nothing to do
};
Demo
I think this is the most idiomatic way in C++11 for delegating to different implementations based on type traits. In many situations, tag dispatching can replace if constexpr (from C++17, not C++14), and I believe the latter always replaces the former in addition to being clearer. Tag dispatching can also be used before C++11 if you roll your own type traits.
Last note: you don't need to use the standard type traits, you can do something like this:
template <typename T> struct is_ptr { static const bool value = false; };
template <typename T> struct is_ptr<T*> { static const bool value = true; };
template <typename T> struct is_ptr<T* const> { static const bool value = true; };
template <typename T> struct is_ptr<T* volatile> { static const bool value = true; };
template <typename T> struct is_ptr<T* const volatile> { static const bool value = true; };
template<bool b>
struct bool_constant {};
template<typename T>
struct Box {
T data;
~Box() {
destroy(bool_constant<is_ptr<T>::value>{});
}
private:
void destroy(bool_constant<true>) {
delete data;
}
void destroy(bool_constant<false>) {} // nothing to do
};
Demo
However, this pretty much amounts to recreating the standard type traits, but probably worse. Just use the standard library when possible.
I think you had the right idea with the helper type, but I'd do it like the following example illustrates.
template <typename B, typename T>
struct BoxTraits {
static T& get_data(B *const box) { return box->data; }
// ^--- important
static T const& get_data(B const* const box) { return box->data; }
};
template <typename T>
struct BoxTraits<Box<T*>, T> {
static T& get_data(Box<T*>* const box) { return *box->data; }
static T const& get_data(Box<T*> const* const box) { return *box->data; }
};
Both versions always return T, so you can use them the same regardless of your Box's payload. You could add a type alias in Box so you don't have to pass the template arguments:
typedef Traits BoxTraits<Box, T>; // in Box class

Accessing functions of a derived crtp class from the base calls

I need to be able to access a static method of the derived class, from within a base CRTP class. Is there a way in which I can achieve this?
Here is example code:
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
constexpr static int size()
{
return Derived::size();
}
template<typename T, REQUIRES(size() == 1)>
operator T() const;
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size()
{
return 1;
}
};
Deriving from ExpressionBase<Derived> involves the instantiation of ExpressionBase<Derived>, therefore involves the declaration of the entity
template<typename T, REQUIRES(size() == 1)>
operator T() const;
Here, std::enable_if_t got a template argument that is ill-formed (because Derived isn't complete yet). The SFINAE rule does not apply here, because the ill-formed expression is not in direct context of template argument type, thus it is treated as a hard error.
In order to make the ill-formation happen at an immediate context, use the following code:
#include <type_traits>
template <bool B, class T>
struct lazy_enable_if_c {
typedef typename T::type type;
};
template <class T>
struct lazy_enable_if_c<false, T> {};
template <class Cond, class T>
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
template <class T>
struct type_wrapper {
using type = T;
};
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
struct MyCond {
static constexpr bool value = Derived::size() == 1;
};
template<typename T, typename = typename lazy_enable_if<MyCond, type_wrapper<T>>::type>
operator T () const {
return T{};
}
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size() {
return 1;
}
};
int main() {
Derived d;
int i = d;
return 0;
}
It is actually adapted from boost, which you can find more details here.

boost concept check operator() overload

template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}

Defining traits for templatised classes

I understand how to create type traits and then specialise for a particular class, but in my case I would like to specialise for a class template. The code below does not compile, but the idea is that the specialisation of Traits for MyTemplatisedClass should work for which ever type the user decides to use with MyTemplatisedType.
class Traits
{
public:
static bool someProperty(void) { return false; }
};
template<typename Type>
class MyTemplatisedClass
{
};
template<typename Type>
template<>
class Traits< MyTemplatisedClass<Type> >
{
public:
static bool someProperty(void) { return true; }
};
int main(int argc, char* argv[])
{
std::cout << Traits< MyTemplatisedClass<float> >::someProperty() <<std::endl; //This should be true
return 0;
}
Is this possible or am I asking too much? According to the compiler the first problem is
error C2989: 'Traits' : class template has already been declared as a non-class template
Which is correct, but how do I fix this? If it makes any difference I don't need it to work for non-templatised classes, just templatised ones is fine. Edit: Actually it would be nice if it worked for both templatised and non-templatised classes.
Traits needs to be a template in order to be specialized.
In the specialization drop the line with empty <>: this isn't a template nested within a template or something.
template <typename Type> //can only specialize templates
class Traits
{
public:
static bool someProperty(void) { return false; }
};
template<typename Type>
class MyTemplatisedClass
{
};
template<typename Type>
//template<> //Too much here
class Traits< MyTemplatisedClass<Type> >
{
public:
static bool someProperty(void) { return true; }
};
But if you meant the specialization for any template with one type argument, then that would be:
template < template <class> class SomeTemplatizedType, class Type>
// ^^^^^^^^^^^^^^^^^^^^^^
// names a template, not type
class Traits< SomeTemplatizedType<Type> >;
// ^^^^^^^^^^^^^^^^^^^ ^
// template name |
// argument
The initial class needs to be the "base case", that is, templated to accept any type argument. Then you can worry about what other specializations you'd like to invoke.
template<typename T> class Traits
{
public:
static bool someProperty(void) { return false; }
};
template<typename Type>
class MyTemplatisedClass
{
};
template<typename Type> class Traits< MyTemplatisedClass<Type> >
{
public:
static bool someProperty(void) { return true; }
};
In order to actually use this in compile-time computation, you will need to make it an ICE- integral constant expression. A function cannot be constexpr even if, trivially, it's value is knowable at compile-time. As it stands, I cannot do, for example,
template<typename T> std::enable_if<Traits<T>::value, sometype> somefunc();
The problem is that you've declared Traits as a class, not a class template. Just add template<typename> to the definition of Traits, and remove the spurious template<> from the specialisation and it should be fine.
template<typename> // <--- Add this
class Traits
{
public:
static bool someProperty(void) { return false; }
};
template<typename Type>
class MyTemplatisedClass
{
};
template<typename Type>
// template<> // <--- Remove this
class Traits< MyTemplatisedClass<Type> >
{
public:
static bool someProperty(void) { return true; }
};
int main(int argc, char* argv[])
{
std::cout << Traits< MyTemplatisedClass<float> >::someProperty() <<std::endl; //This should be true
return 0;
}

Check if template argument is inherited from class

I want to check if the type given to a template is inherited from a base class in my project.
It should work like one would expect it from the following example:
template< class T : public CBaseClass >
Is it possible to do this with templates, if not, how else can I do it?
Following an example from Stroustrup:
template<class Test, class Base>
struct AssertSameOrDerivedFrom {
AssertSameOrDerivedFrom() { &constraints; }
public:
static void constraints() {
Test *pd = 0;
Base *pb = pd;
}
};
template<class T>
struct YourClass {
YourClass() {
AssertSameOrDerivedFrom<T, CBaseClass>();
}
};
In C++0x, this becomes:
template<class T>
struct YourClass {
static_assert(std::is_base_of<CBaseClass, T>::value);
};
You can use boost::is_base_and_derived from Boost, combined with BOOST_STATIC_ASSERT. If you are using a compiler with TR1 or C++0x support, there are equivalents of those constructs in the standard library (std::is_base_of, and the static_assert statement in C++0x).
If you want to assert, do it Nurk's way. If you want to check, use is_base_of from boost or C++0x. If you can't use either of those, use SFINAE:
template < typename Base, typename PotentialDerived >
struct is_base
{
typedef char (&no) [1];
typedef char (&yes) [2];
static yes check(Base*);
static no check(...);
enum { value = sizeof(check(static_cast<PotentialDerived*>(0))) == sizeof(yes) };
};
The simplest solution seems to be std::is_base_of:
static_assert(std::is_base_of_v<CBaseClass, T>);
You can of course also use it in combination with if constexpr:
if constexpr (std::is_base_of_v<CBaseClass, T>) {
//
} else {
//
}
See cppreference for more details:
https://en.cppreference.com/w/cpp/types/is_base_of
Shorter is better:
template <typename Base, typename Derived>
struct is_base {
constexpr static bool check(Base*) { return true; }
constexpr static bool check(...) { return false; }
enum { value = check(static_cast<Derived*>(0)) };
};
Example 1:
struct A {};
struct B : A { };
int main(void) {
static_assert(is_base<A,B>::value, "If Error: A is not base of B");
}
Example 2:
template <bool, typename T=void>
struct Use {
static std::string info() { return "Implementation that consider that A is not base of B"; }
};
template <typename T>
struct Use<true,T> {
static std::string info() { return "Implementation that consider that A is the base of B"; }
};
int main(void) {
std::cout << Use<is_base<A,B>::value>::info(); //Implementation that consider that A is the base of B
}