c++ template specialization for all subclasses - c++

I need to create a template function like this:
template<typename T>
void foo(T a)
{
if (T is a subclass of class Bar)
do this
else
do something else
}
I can also imagine doing it using template specialization ... but I have never seen a template specialization for all subclasses of a superclass. I don't want to repeat specialization code for each subclass

You can do what you want but not how you are trying to do it! You can use std::enable_if together with std::is_base_of:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar { virtual ~Bar() {} };
struct Foo: Bar {};
struct Faz {};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is derived from Bar\n";
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is NOT derived from Bar\n";
}
int main()
{
foo("Foo", Foo());
foo("Faz", Faz());
}
Since this stuff gets more wide-spread, people have discussed having some sort of static if but so far it hasn't come into existance.
Both std::enable_if and std::is_base_of (declared in <type_traits>) are new in C++2011. If you need to compile with a C++2003 compiler you can either use their implementation from Boost (you need to change the namespace to boost and include "boost/utility.hpp" and "boost/enable_if.hpp" instead of the respective standard headers). Alternatively, if you can't use Boost, both of these class template can be implemented quite easily.

I would use std::is_base_of along with local class as :
#include <type_traits> //you must include this: C++11 solution!
template<typename T>
void foo(T a)
{
struct local
{
static void do_work(T & a, std::true_type const &)
{
//T is derived from Bar
}
static void do_work(T & a, std::false_type const &)
{
//T is not derived from Bar
}
};
local::do_work(a, std::is_base_of<Bar,T>());
}
Please note that std::is_base_of derives from std::integral_constant, so an object of former type can implicitly be converted into an object of latter type, which means std::is_base_of<Bar,T>() will convert into std::true_type or std::false_type depending upon the value of T. Also note that std::true_type and std::false_type are nothing but just typedefs, defined as:
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

I know this question has been answered but nobody mentioned that std::enable_if can be used as a second template parameter like this:
#include <type_traits>
class A {};
class B: public A {};
template<class T, typename std::enable_if<std::is_base_of<A, T>::value, int>::type = 0>
int foo(T t)
{
return 1;
}

I like this clear style:
void foo_detail(T a, const std::true_type&)
{
//do sub-class thing
}
void foo_detail(T a, const std::false_type&)
{
//do else
}
void foo(T a)
{
foo_detail(a, std::is_base_of<Bar, T>::value);
}

The problem is that indeed you cannot do something like this in C++17:
template<T>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T> {
// T should be subject to the constraint that it's a subclass of X
}
There are, however, two options to have the compiler select the correct method based on the class hierarchy involving tag dispatching and SFINAE.
Let's start with tag dispatching. The key here is that tag chosen is a pointer type. If B inherits from A, an overload with A* is selected for a value of type B*:
#include <iostream>
#include <type_traits>
struct type_to_convert {
type_to_convert(int i) : i(i) {};
type_to_convert(const type_to_convert&) = delete;
type_to_convert(type_to_convert&&) = delete;
int i;
};
struct X {
X(int i) : i(i) {};
X(const X &) = delete;
X(X &&) = delete;
public:
int i;
};
struct Y : X {
Y(int i) : X{i + 1} {}
};
struct A {};
template<typename>
static auto convert(const type_to_convert &t, int *) {
return t.i;
}
template<typename U>
static auto convert(const type_to_convert &t, X *) {
return U{t.i}; // will instantiate either X or a subtype
}
template<typename>
static auto convert(const type_to_convert &t, A *) {
return 42;
}
template<typename T /* requested type, though not necessarily gotten */>
static auto convert(const type_to_convert &t) {
return convert<T>(t, static_cast<T*>(nullptr));
}
int main() {
std::cout << convert<int>(type_to_convert{5}) << std::endl;
std::cout << convert<X>(type_to_convert{6}).i << std::endl;
std::cout << convert<Y>(type_to_convert{6}).i << std::endl;
std::cout << convert<A>(type_to_convert{-1}) << std::endl;
return 0;
}
Another option is to use SFINAE with enable_if. The key here is that while the snippet in the beginning of the question is invalid, this specialization isn't:
template<T, typename = void>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T, void> {
}
So our specializations can keep a fully generic first parameter as long we make sure only one of them is valid at any given point. For this, we need to fashion mutually exclusive conditions. Example:
template<typename T /* requested type, though not necessarily gotten */,
typename = void>
struct convert_t {
static auto convert(const type_to_convert &t) {
static_assert(!sizeof(T), "no conversion");
}
};
template<>
struct convert_t<int> {
static auto convert(const type_to_convert &t) {
return t.i;
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<X, T>>> {
static auto convert(const type_to_convert &t) {
return T{t.i}; // will instantiate either X or a subtype
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<A, T>>> {
static auto convert(const type_to_convert &t) {
return 42; // will instantiate either X or a subtype
}
};
template<typename T>
auto convert(const type_to_convert& t) {
return convert_t<T>::convert(t);
}
Note: the specific example in the text of the question can be solved with constexpr, though:
template<typename T>
void foo(T a) {
if constexpr(std::is_base_of_v<Bar, T>)
// do this
else
// do something else
}

If you are allowed to use C++20 concepts, all this becomes almost trivial:
template<typename T> concept IsChildOfX = std::is_base_of<X, T>::value;
// then...
template<IsChildOfX X>
void somefunc( X& x ) {...}

Related

aggregate-initializable tuple like data structure

I want to store multiple non-movable types in a single variable.
At the very first, I have tried std::tuple at the very first, but it fails.
#include <tuple>
template<typename T>
struct No {
No(T){}
No(const No &) = delete;
No(No &&) = delete;
};
struct Handmade {
No<int> a;
No<double> b;
No<char> c;
};
template<typename T>
auto no() -> No<T> { return No<T>(T()); }
auto main() -> int
{
Handmade h = {no<int>(), no<double>(), no<char>()}; // good
auto tuple = std::make_tuple(no<int>(), no<double>(), no<char>()); // fails
return 0;
}
Here, Handmade type can be initialized through aggregate initialization.
However, std::tuple is not aggregate-initialzable, it doesn't work.
Since it should be variadic, I cannot write such type Handmade for my purpose.
Is it possible to implement such variadic tepmlate data structure in current C++ standard or is there any workaround?
Yes, you can write your own aggregate tuple like this:
template <int I, typename T>
struct MyTupleElem
{
T value{};
template <int J> requires(I == J) T &get() {return value;}
template <int J> requires(I == J) const T &get() const {return value;}
};
template <typename T, typename ...P>
struct MyTupleHelper;
template <int ...I, typename ...P>
struct MyTupleHelper<std::integer_sequence<int, I...>, P...>
: MyTupleElem<I, P>...
{
using MyTupleElem<I, P>::get...;
};
template <typename ...P>
struct MyTuple : MyTupleHelper<std::make_integer_sequence<int, sizeof...(P)>, P...> {};
template <typename ...P>
MyTuple(P &&...) -> MyTuple<std::decay_t<P>...>;
template <typename T>
struct No
{
T value;
No(T value) : value(value) {}
No(const No &) = delete;
No(No &&) = delete;
};
template <typename T>
No<T> no(T t) {return No<T>(t);}
int main()
{
MyTuple h = {no<int>(1), no<double>(2.3), no<char>('4')};
std::cout << h.get<0>().value << '\n';
std::cout << h.get<1>().value << '\n';
std::cout << h.get<2>().value << '\n';
}
And I think it's a good way to make tuples in general, even if you don't want aggregate-ness. Last time I tested, such tuples could tolerate more elements than the classic ones with the bases chained on top of each other.

Check for function existance on other type using C++ concepts

Does anybody know how to make a C++ concept T such that the function g is only defined for arguments t with type T if there exist an overload of f in B that accepts an argument t?
struct A1 {};
struct A2 {};
struct B {
void f(A1 a1) {}
};
void g(T t) {
B b;
b.f(t);
}
As an example, I want to define a to_string for everything that std::stringstream accepts, and define something like
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
All examples on concepts deal with the easier case of requiring the existance of a function on a type, while in this case we want to check existance of a function on another type.
If you want to check if the type is streamable or not, you can have something like:
#include <iostream>
#include <concepts>
#include <sstream>
template <typename T>
concept Streamable = requires (T x, std::ostream &os) { os << x; };
struct Foo {};
struct Bar {};
std::ostream& operator<<(std::ostream& os, Foo const& obj) {
// write obj to stream
return os;
}
template <Streamable T>
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
int main() {
Foo f;
Bar b;
to_string(f);
to_string(b); // error
return 0;
}
Demo
You can use two different type placeholders in a single concept, to require both the existence of a member function for an instance of one of the type placeholders, as well as the argument to said member function to match the type of another placeholder. E.g.:
#include <iostream>
template<typename T, typename U>
concept HasMemFnConstFoo = requires(const T t, const U u) {
t.foo(u);
};
template<typename U>
struct Bar {
template <typename T>
static void bar(const T& t)
{
if constexpr (HasMemFnConstFoo<T, U>) { t.foo(U{}); }
else { std::cout << "foo() not defined\n"; }
}
};
struct A1 {};
struct A2 {};
struct B1 {
void foo(const A1&) const { std::cout << "B1::foo()\n"; }
};
struct B2 {
void foo(const A1&) { std::cout << "B2::foo()\n"; }
};
struct B3 {
void foo(A1&) const { std::cout << "B3::foo()\n"; }
};
int main() {
Bar<A1>::bar(B1{}); // B1::foo()
Bar<A2>::bar(B1{}); // foo() not defined
Bar<A1>::bar(B2{}); // foo() not defined [note: method constness]
Bar<A2>::bar(B2{}); // foo() not defined
Bar<A1>::bar(B3{}); // foo() not defined [note: argument constness]
Bar<A2>::bar(B3{}); // foo() not defined
}

How to check if union contains type (using type_traits)?

I have a function template like the following:
template<class U, class T>
T* unsafeCast(U* theUnion) {
reinterpret_cast<T*>(theUnion);
}
How can I make sure this only compiles if T is a type contained within the union U, so that the following holds?
union FooUnion {
int a;
double b;
} foo;
unsafeCast<FooUnion, int>(&foo); // compiles
unsafeCast<FooUnion, double>(&foo); // compiles
unsafeCast<FooUnion, char>(&foo); // does not compile
I understand that is_union from <type_traits> allows to check for a union, but how can I check for types within a union?
You cannot.
boost::variant and std::variant are solutions to this problem such that the union carries with it the type information you need.
You could create a raw union like this:
template<class T>
struct data_holder {
T data;
};
template<class...Ts>
struct union_data;
template<>
struct union_data<>{};
template<class T0>
struct union_data<T0>:data_holder<T0> {};
template<class T0, class...Ts>
struct union_data<T0, Ts...> {
union {
union_data<T0> lhs;
union_data<Ts...> rhs;
};
};
template<class...Ts>
struct raw_union:union_data<Ts...>{
template<class T>
constexpr static bool valid_type() {
return (std::is_same<T, Ts>{}||...); // rewrite in C++14/11
}
template<class T>
union_data<T>* get_data_ptr() {
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T>*>(this);
}
template<class T>
union_data<T> const* get_data_ptr() const{
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T> const*>(this);
}
template<class T>
T& get_unsafe() {
return get_data_ptr<T>()->data;
}
template<class T>
T const& get_unsafe() const {
return get_data_ptr<T>()->data;
}
template<class T, class...Us>
T& emplace( Us&&... us ) {
auto* ptr = ::new( (void*)get_data_ptr<T>() ) union_data<T>{ T(std::forward<Us>(us)...) };
return ptr->data;
}
template<class T>
void dtor() {
get_data_ptr<T>()->~T();
}
};
which is unsafe and undiscriminated, but does check if foo.get_unsafe<int>() actually contains an int.
live example.
Use:
raw_union<int, double> un;
un.emplace<int>(7);
std::cout << un.get_unsafe<int>() << "\n";
it does not support multiple union members of the same type. You are in charge of calling .emplace<T>(x) before using T, and if a non-trivial destructor .dtor<T>().
Accessing members that are not active is just as perilous as doing so with raw C/C++ unions.
If you can add constructors to your unions you can do it like this:
#include <type_traits>
// Use std::void_t to only allow types that the union can be constructed from
template<class T, class U, class = std::void_t<decltype(U{std::declval<T>()})>>
T* unsafeCast(U* theUnion) {
return reinterpret_cast<T*>(theUnion);
}
union FooUnion {
int a;
double b;
// Explictly add constructors for each desired type
FooUnion(int a) : a{a} {}
FooUnion(double b) : b{b} {}
// Add a deleted catch all to prevent implicit conversions, e.g. from char
template <class T>
FooUnion(T) = delete;
} foo(0);
int main() {
unsafeCast<int>(&foo); // compiles
unsafeCast<double>(&foo); // compiles
unsafeCast<char>(&foo); // does not compile
}
Godbolt

C++ method with multiple parameter packs

Consider the following simplified piece of code for a variant class. Most of it is for informational purposes, the question is about the conditional_invoke method.
// Possible types in variant.
enum class variant_type { empty, int32, string };
// Actual data store.
union variant_data {
std::int32_t val_int32;
std::string val_string;
inline variant_data(void) { /* Leave uninitialised */ }
inline ~variant_data(void) { /* Let variant do clean up. */ }
};
// Type traits which allow inferring which type to use (these are actually generated by a macro).
template<variant_type T> struct variant_type_traits { };
template<class T> struct variant_reverse_traits { };
template<> struct variant_type_traits<variant_type::int32> {
typedef std::int32_t type;
inline static type *get(variant_data& d) { return &d.val_int32; }
};
template<> struct variant_reverse_traits<std::int32_t> {
static const variant_type type = variant_type::int32;
inline static std::int32_t *get(variant_data& d) { return &d.val_int32; }
};
template<> struct variant_type_traits<variant_type::string> {
typedef std::string type;
inline static type *get(variant_data& d) { return &d.val_string; }
};
template<> struct variant_reverse_traits<std::string> {
static const variant_type type = variant_type::string;
inline static std::string *get(variant_data& d) { return &d.val_string; }
};
// The actual variant class.
class variant {
public:
inline variant(void) : type(variant_type::empty) { }
inline ~variant(void) {
this->conditional_invoke<destruct>();
}
template<class T> inline variant(const T value) : type(variant_type::empty) {
this->set<T>(value);
}
template<class T> void set(const T& value) {
this->conditional_invoke<destruct>();
std::cout << "Calling data constructor ..." << std::endl;
::new (variant_reverse_traits<T>::get(this->data)) T(value);
this->type = variant_reverse_traits<T>::type;
}
variant_data data;
variant_type type;
private:
template<variant_type T> struct destruct {
typedef typename variant_type_traits<T>::type type;
static void invoke(type& v) {
std::cout << "Calling data destructor ..." << std::endl;
v.~type();
}
};
template<template<variant_type> class F, class... P>
inline void conditional_invoke(P&&... params) {
this->conditional_invoke0<F, variant_type::int32, variant_type::string, P...>(std::forward<P>(params)...);
}
template<template<variant_type> class F, variant_type T, variant_type... U, class... P>
void conditional_invoke0(P&&... params) {
if (this->type == T) {
F<T>::invoke(*variant_type_traits<T>::get(this->data), std::forward<P>(params)...);
}
this->conditional_invoke0<F, U..., P...>(std::forward<P>(params)...);
}
template<template<variant_type> class F, class... P>
inline void conditional_invoke0(P&&... params) { }
};
The code works this way, i.e. it works as long as the parameter list P... for the functor is empty. If I add another functor like
template<variant_type T> struct print {
typedef typename variant_type_traits<T>::type type;
static void invoke(type& v, std::ostream& stream) {
stream << v;
}
};
and try to invoke it
friend inline std::ostream& operator <<(std::ostream& lhs, variant& rhs) {
rhs.conditional_invoke<print>(lhs);
return lhs;
}
the compiler VS 20115 complains
error C2672: 'variant::conditional_invoke0': no matching overloaded function found
or gcc respectively
error: no matching function for call to 'variant::conditional_invoke0 >&>(std::basic_ostream&)'
I guess the compiler cannot decide when U... ends and when P... starts. Is there any way to work around the issue?
You'll have to make both parameter packs deducible. That is, let the type and non-type template parameters be part of a function parameter list. For that, introduce a dummy structure:
template <variant_type...>
struct variant_type_list {};
and let the compiler deduce the variant_type... pack from a function call:
template <template <variant_type> class F
, variant_type T
, variant_type... U
, typename... P>
void conditional_invoke0(variant_type_list<T, U...> t
, P&&... params)
{
if (this->type == T)
{
F<T>::invoke(*variant_type_traits<T>::get(this->data)
, std::forward<P>(params)...);
}
this->conditional_invoke0<F>(variant_type_list<U...>{}
, std::forward<P>(params)...);
}
To break recursive calls, introduce an overload with an empty variant_type_list:
template <template <variant_type> class F, typename... P>
void conditional_invoke0(variant_type_list<>, P&&... params) {}
When calling the invoker for the first time, provide variant_types as an argument:
this->conditional_invoke0<F>(variant_type_list<variant_type::int32, variant_type::string>{}
, std::forward<P>(params)...);
DEMO

How to delegate traits functionality to member of class?

I'm searching for a way to delegate trait functionality to member. Inheritance is not an option at this point.
So assume we have a class B and 2 different Traits already working with that class.
struct B
{};
template<typename T>
struct Trait1
{
static
void foo1(T t)
{}
};
template<>
struct Trait1<B>
{
static
void foo1(B t)
{}
};
template<typename T>
struct Trait2
{
static
void foo2(T t)
{}
};
template<>
struct Trait2<B>
{
static
void foo2(B t)
{}
};
I also have an aggregate class C with 2 members of that class B, like:
struct C
{
B m1;
B m2;
};
Now I want to define the both Traits for that class C as well, with delegating to the appropriate member. The plain approach would be s.th. like:
template<>
struct Trait1<C>
{
static
void foo1(C t)
{
Trait1<B>::foo1(t.m1);
}
};
template<>
struct Trait2<C>
{
static
void foo2(C t)
{
Trait2<B>::foo2(t.m2);
}
};
For traits with a lot of functions that is kind of annoying and probably has copy-paste errors. So the question arised to me, is there a way to delegate the functionality in an elegant way (C++11 preferred, C++14/17 also possible)? Meaning In case of Trait1 use member m1 and for Trait2 use member m2.
Thanks for help.
EDIT: methods of the Trait1 and Trait2 have actually different names.
And in the wild a macro replacing 1 with 2 will not work, so I would encourage not to use macros.
You can create a generic traits for factorize code
template<template <typename> class Trait, typename T, typename T2, T2 (T::*M)>
struct GenTrait
{
static
void foo(T t)
{
Trait<T2>::foo(t.*M);
}
};
And then
template<>
struct Trait1<C> : GenTrait<Trait1, C, B, &C::m1> {};
template<>
struct Trait2<C> : GenTrait<Trait2, C, B, &C::m2> {};
First, I needed executor template functions. These are the ones to do perform whatever has to be done and to be specialised or overloaded for other classes:
template<typename T>
void theFoo1(T t)
{
std::cout << "foo 1" << std::endl;
}
template<typename T>
void theFoo2(T t)
{
std::cout << "foo 2" << std::endl;
}
struct B
{};
void theFoo1(B t)
{
std::cout << "foo 1 B" << std::endl;
}
void theFoo2(B t)
{
std::cout << "foo 2 B" << std::endl;
}
Then, I need getter templates that provide the appropriate data:
template<typename T>
inline T get1(T t)
{
return t;
}
template<typename T>
inline T get2(T t)
{
return t;
}
My traits no look like this; note: you won't specialise these any more at any time:
template<typename T>
struct Trait1
{
static inline
void foo(T t)
{
theFoo1(get1(t));
}
};
template<typename T>
struct Trait2
{
static inline
void foo(T t)
{
theFoo2(get2(t));
}
};
Now C comes into play; B is already ready for use, so we can simply continue with C itself; all I need is two additional overloads:
struct C
{
B m1;
B m2;
};
B get1(C t)
{
return t.m1;
}
B get2(C t)
{
return t.m2;
}
Finally: test it...
int main(int, char*[])
{
B b;
Trait2<B>::foo(b);
C c;
Trait1<C>::foo(c);
Trait2<C>::foo(c);
}
Due to your specific requirement (where you need m1 & m2), there is no way to avoid re-writing lot of code for class C separately. To avoid such copy pasting, you may use simple macros. Pseudo code:
#define TRAIT_C(N, FUNCTION) \
template<> \
struct Trait##N<C> \
{ \
static \
void foo(C t) \
{ \
Trait##N<B>::foo(t.m##N); \
} \
}
Now use this in a "eye-soothing" way while defining trait for B:
template<>
struct Trait1<B>
{
static
void foo(B t)
{}
};
TRAIT_C(1, foo); // This inlines the complete version of `Trait1` for `C`
Here is a demo-ideone or demo-coliru.
You can expose the pointers to data members as part of the traits itself.
It can be done by means of template variables (named data in the example below).
It follows a minimal, working example:
struct B {};
template<typename T>
struct Trait1;
template<>
struct Trait1<B>
{
template<typename U>
static constexpr B U::* data = &U::m1;
static
void foo(B t)
{}
};
template<typename T>
struct Trait2;
template<>
struct Trait2<B>
{
template<typename U>
static constexpr B U::* data = &U::m2;
static
void foo(B t)
{}
};
struct C
{
B m1;
B m2;
};
template<>
struct Trait1<C>
{
using BT = Trait1<B>;
static constexpr B C::* data = BT::data<C>;
static
void foo(C t)
{
BT::foo(t.*data);
}
};
template<>
struct Trait2<C>
{
static
void foo(C t)
{
Trait2<B>::foo(t.*Trait2<B>::data<C>);
}
};
In the example above, Trait1<C> and Trait2<C> differ in order to show two possible solutions (I would use the first one if I had the same problem).
After inspiration by some of the proposals (e.g. #Aconcagua ) I thought of a DelegateTrait itself, like:
#include <iostream>
template<typename TraitT, typename DelegateT>
struct DelegateTrait
{
typedef DelegateT MemberT;// type of member delegated to
// method for delegation to specific member
static
MemberT forward(DelegateT delegate)
{
return delegate;
}
};
Now a small adaption of the original Trait1 is needed
template<typename T, typename DelegateT = void>
struct Trait1
{
static
void foo1(T t)
{
std::cout << "default Trait1<T>::foo1()" << std::endl;
}
};
template<typename T>
struct Trait1<
T,
typename std::enable_if<!std::is_same<T, typename DelegateTrait<Trait1<T>, T>::MemberT>::value>::type>
{
static
void foo1(T t)
{
std::cout << "delegate Trait1<T>::foo1()" << std::endl;
Trait1<typename DelegateTrait<Trait1<T>, T>::MemberT>::foo1(DelegateTrait<Trait1<T>, T>::forward(t));
}
};
template<>
struct Trait1<B>
{
static
void foo1(B t)
{
std::cout << "Trait1<B>::foo1()" << std::endl;
}
};
In a similar way an adaption of Trait2 is done. The std::enable_if is used to avoid recursive (and endless) calling of the same method.
You now have to specialize the DelegateTrait for each combination of class and trait where you want to forward to s.th. else but the instance of the given class.
template<>
struct DelegateTrait<Trait1<C>, C>
{
typedef B MemberT;
static
MemberT forward(C delegate)
{
std::cout << "forward C to C.m1" << std::endl;
return delegate.m1;
}
};
template<>
struct DelegateTrait<Trait2<C>, C>
{
typedef B MemberT;
static
MemberT forward(C delegate)
{
std::cout << "forward C to C.m2" << std::endl;
return delegate.m2;
}
};
You can still specialize for the class itself if you don't want to forward, like:
struct D
{
D(){};
B m1;
B m2;
};
template<>
struct Trait2<D>
{
static
void foo2(D t)
{
std::cout << "Trait<D>::foo2(), no delegate" << std::endl;
}
};
int
main(
int argc,
char ** argv)
{
C c;
Trait1<C>::foo1(c);//delegates to m1
Trait2<C>::foo2(c);//delegates to m2
D d;
Trait1<D>::foo1(d);//default trait implementation
Trait2<D>::foo2(d);//trait specialization for D
return 0;
}
Of course that solution needs a extension of the original trait. Do you see some other issue coming with that approach, e.g. performance?