Template specialization based on inherit class - c++

I want to make this specialized w/o changing main. Is it possible to specialize something based on its base class? I hope so.
-edit-
I'll have several classes that inherit from SomeTag. I don't want to write the same specialization for each of them.
class SomeTag {};
class InheritSomeTag : public SomeTag {};
template <class T, class Tag=T>
struct MyClass
{
};
template <class T>
struct MyClass<T, SomeTag>
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //how do i make this specialized w/o changing main()
return 0;
}

This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm
Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):
template<typename D, typename B>
class IsDerivedFrom
{
class No { };
class Yes { No no[3]; };
static Yes Test( B* ); // not defined
static No Test( ... ); // not defined
static void Constraints(D* p) { B* pb = p; pb = p; }
public:
enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
IsDerivedFrom() { void(*p)(D*) = Constraints; }
};
Then your MyClass needs an implementation that's potentially specialized:
template<typename T, int>
class MyClassImpl
{
// general case: T is not derived from SomeTag
};
template<typename T>
class MyClassImpl<T, 1>
{
// T is derived from SomeTag
public:
typedef int isSpecialized;
};
and MyClass actually looks like:
template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};
Then your main will be fine the way it is:
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}

And the short version now, 2014, using C++-11:
#include <type_traits>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, bool = std::is_base_of<SomeTag, T>::value>
struct MyClass { };
template<typename T>
struct MyClass<T, true> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}

Well, the article in the answer above appeared in February 2002. While it works, today we know there are better ways. Alternatively, you can use enable_if:
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<typename B, typename D>
struct is_base_of {
static D * create_d();
static char (& chk(B *))[1];
static char (& chk(...))[2];
static bool const value = sizeof chk(create_d()) == 1 &&
!is_same<B volatile const,
void volatile const>::value;
};
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, typename = void>
struct MyClass { /* T not derived from SomeTag */ };
template<typename T>
struct MyClass<T, typename enable_if<is_base_of<SomeTag, T>::value>::type> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}

In your case, the only way that I see would be to explicitly specialize MyClass for InheritSomeTag. However, the SeqAn paper proposes a mechanism called “template sublassing” that does what you want – albeit with a different inheritance syntax, so the code isn't compatible with your current main function.
// Base class
template <typename TSpec = void>
class SomeTag { };
// Type tag, NOT part of the inheritance chain
template <typename TSpec = void>
struct InheritSomeTag { };
// Derived class, uses type tag
template <typename TSpec>
class SomeTag<InheritSomeTag<TSpec> > : public SomeTag<void> { };
template <class T, class Tag=T>
struct MyClass { };
template <class T, typename TSpec>
struct MyClass<T, SomeTag<TSpec> >
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag<> >::isSpecialized test1; //ok
MyClass<SomeTag<InheritSomeTag<> > >::isSpecialized test2; //ok
}
This certainly looks strange and is very cumbersome but it allows a true inheritance mechanism with polymorphic functions that is executed at compile time. If you want to see this in action, have a look at some SeqAn examples.
That being said, I believe that SeqAn is a special case and not many applications would profit from this extremely difficult syntax (deciphering SeqAn-related compiler errors is a real pain in the *ss!)

Using concepts and the requires keyword from C++20 is an even simpler and more expressive way to do this without having to introduce a redundant boolean non-type template parameter like in C++11:
// C++20:
#include <concepts>
#include <iostream>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T>
struct MyClass
{
void Print()
{
std::cout << "Not derived from someTag\n";
}
};
// std::derived_from is a predefined concept already included in the STL
template<typename T>
requires std::derived_from<T, SomeTag>
struct MyClass<T>
{
void Print()
{
std::cout << "derived from someTag\n";
}
};
int main()
{
MyClass<InheritSomeTag> test1;
test1.Print(); // derived from someTag
MyClass<int> test2;
test2.Print(); // Not derived from someTag
// Note how even the base tag itself returns true from std::derived_from:
MyClass<SomeTag> test3;
test3.Print(); // derived from someTag
}

Related

Change class API depending on template parameter at class creation

I was looking to create a class that under specific template instantiation would expose a different API. It has common functions, but a few should be disabled in the case that the user will use a specific instantiation of the class. Something like this:
VarApi<T1> v1;
v1.common();
v1.funcA1();
// v1.funcA2(); // ERROR
v1.funcA1_2();
VarApi<T2> v2;
v1.common();
// v2.funcA1(); // ERROR
v2.funcA2();
v2.funcA1_2();
VarApi<T3> v3;
v3.common();
// v2.funcA1(); // ERROR
// v2.funcA2(); // ERROR
// v1.funcA1_2(); // ERROR
I found that you could achieve this with SFINAE and std::enable_if like this:
enum Type { T1, T2, T3 };
template <Type TType> struct VarApi {
void common() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1>::type>
void funcA1() { }
template <Type T = TType,
typename = typename std::enable_if<T == T2>::type >
void funcA2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1 || T == T2>::type >
void funcA1_2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T3>::type >
void funcA3() { }
};
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
Sure.
You can impose that T and TType are the same type
template <Type T = TType,
typename = typename std::enable_if<
std::is_same<T, T1>::value
&& std::is_same<T, TType>::value>::type>
void funcA1() { }
This prevent the template "hijacking".
You can exploit inheritance to provide desired functions. With CRTP, you access functionality of the original class in the func_provider by self pointer.
template<class T, class Derived> struct func_provider;
template<class Derived>
struct func_provider<int, Derived> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
template<class Derived> struct func_provider<double, Derived> { void funcA2() {} };
template<class T>
struct foo : public func_provider<T, foo<T>> {};
int main() {
foo<int> f;
foo<double> g;
f.funcA1();
// f.funcA2(); // Error
g.funcA2();
// g.funcA1(); // Error
}
EDIT:
This version allows the user to implement function for multiple types in one place, user can combine types together:
template<class... Ts> struct types {};
template<class Types, class T> struct is_in : public std::false_type {};
template<class... Ts, class T>
struct is_in<types<T, Ts...>, T> : public std::true_type {};
template<class... Ts, class T0, class T>
struct is_in<types<T0, Ts...>, T> : public is_in<types<Ts...>, T> {};
template<class Derived, bool B, class T> struct func_provider {};
template<class Derived, class T, class... Ts>
struct func_collector
: public func_provider<Derived, is_in<Ts, T>::value, Ts>...
{};
// implement functions for int
template<class Derived>
struct func_provider<Derived, true, types<int>> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
// implement functions for double
template<class Derived>
struct func_provider<Derived, true, types<double>> { void funcA2() {} };
// implement functions for both int and double
template<class Derived>
struct func_provider<Derived, true, types<int, double>> { void funcA1_2() {} };
template<class T>
struct foo : public func_collector<foo<T>, T,
// pull desired functions
types<int>, types<double>, types<int, double>>
{
void common() {}
};
int main() {
foo<int> f;
foo<double> g;
f.common();
f.funcA1();
f.funcA1_2();
// f.funcA2(); // Error
g.funcA2();
g.funcA1_2();
// g.funcA1(); // Error
}
Solution 1
One way to achieve what you ask for is to use tempalte specialization and dependent base classes to offer the optional functionalities.
// I'm using E for enum. I find TType a bit misleading, since T usually stands for Type
template< Type EType >
struct VarApiBase { }; // empty by default
template< >
struct VarApiBase<T1> {
void funcA1() { }
};
template< >
struct VarApiBase<T2> {
void funcA2() { }
};
template <Type TType>
struct VarApi : VarApiBase<TType> {
void funcA1_2() { }
};
template <>
struct VarApi<T3> { };
I'm not particularly fond of this solution. Because it becomes complex to provide shared functions (I put funcA1_2 in VarApi, and not in the base, and then specialized VarApi again to disable it for T3, but this is forcing you to explicitly specialize every time you add a new EType value. You could get around it with an enabler for the specialization, but it again become complex if you have more intricate sharing).
If you need it, you can give VarApiBase access to VarApi by declaring it a friend in VarApi.
Solution 2
As a cheap alternative to all of this, you may just add a static_assert inside your functions:
template <Type ETypeInner = EType >
void funcA1_2() {
static_assert(ETypeInner==EType);
static_assert(EType == T1 || EType == T2);
}
If you really need SFINAE, you can still put the ==T1 || ==T2 condition in the template
template <Type ETypeInner = EType,
typename = typename std::enable_if<ETypeInner == T1 || ETypeInner == T2>::type >
void funcA1_2() {
static_assert(ETypeInner==EType);
}
but be aware it will make compilation slower.
Solution 3
Probably, the cleanest way would be to have explicit specializations and utility functions.
In VarApi.h:
struct VarApiImpl;
template< Type EType >
struct VarApi; // undefined
// Ideally, VarApiCommon shouldn't need to be a template
template< Type EType >
struct VarApiCommon {
// you can put here members and functions which common to all implementations, just for convenience.
void common() { /* ... */ }
private:
// You can do this if you need access to specialization-specific members.
// Ideally, if a function is common, it should only need common members, though.
VarApi<EType> & Derived() { return static_cast<VarApi<EType>&>(*this); }
VarApi<EType> const& Derived() const { return static_cast<VarApi<EType> const&>(*this); }
};
template<>
struct VarApi<T1> : VarApiCommon<T1> {
friend VarApiImpl;
friend VarApiCommon<T1>;
void funcA1();
void funcA1_2();
};
template<>
struct VarApi<T2> : VarApiCommon<T2> {
friend VarApiImpl;
friend VarApiCommon<T2>;
void funcA2();
void funcA1_2();
};
template<>
struct VarApi<T3> : VarApiCommon<T3> {
friend VarApiCommon<T3>;
};
In VarApi.cpp:
struct VarApiImpl final {
// Here go the functions which are only shared by some specializations
template< Type EType >
static void funcA1_2(VarApi<EType>& vapi) {
// Just for sanity. Since this function is private to the .cpp, it should be impossible to call it inappropriately
static_assert(EType==T1 || EType==T2);
// ...
}
};
void VarApi<T1>::funcA1() { /* ... */ }
void VarApi<T1>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
void VarApi<T2>::funcA2() { /* ... */ }
void VarApi<T2>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
It gets as verbose as C++ can be, but at least you have explicit interfaces clearly stating what's offered and what's not, without having to read a bunch of enable_ifs.
Solution 4
Ultimately, I would suggest you to look more carefully at your requirements, to see if they can't be expressed as a proper class hierarchy, based on the features each enum value represents. C++ even has virtual inheritance, if you need to avoid duplicate bases. For instance, that'd be possible in your example:
struct VarApiCommon {
void common();
};
struct VarApi12 : VarApiCommon {
void funcA1_2();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApiCommon {
void funcA3();
};
If you had a funcA2_3, for instance, you may still be able to do it this way:
struct VarApiCommon {
void common();
};
struct VarApi12 : virtual VarApiCommon {
void funcA1_2();
};
struct VarApi23 : virtual VarApiCommon {
void funcA2_3();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12, VarApi23 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApi23 {
void funcA3();
};
Much depends on the members.
My suggestion is based on you being able to provide the implementation, but wanting to hide it.
Have a base implementation, which implements everything
template <class X> class Base
{
public:
void A();
void B();
void C();
void D();
void E();
};
Have a derived class which inherits protected, but then publishes public all the common methods from the base
template <class X> class Mid: protected Base<X>
{
public:
using Base::A;
using Base::B;
using Base::C;
// D & E are contentious
};
Have the actual published class, where each variant T1, T2, T3 is specialised.
These classes all publicly inherit from the second class, but then public friend publish the methods they do support.
template <class X> class Top: public Mid<X> {};
template <> class Top<X1>: public Mid<X1>
{
public:
using Base::D;
// Can't get E
};
template <> class Top<X2>: public Mid<X2>
{
public:
// Can't get D
using Base::E;
};
Gains: The methods you want to hide are not accessible. There is no template function magic.
Losses: The rules for publishing are arbitrary, and not driven by 'readable' FINAE at all. You also can't easily use inheritance to build rules either, though you might be able to do a LikeX second template argument.

Adapting a template-provided base class

How would you go about filling-in a method if a base class doesn't provide it. I'd like to reuse the base class method if it is provided.
E.g.:
#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };
template<typename T>
struct Derived : public T {
//if T doesn't provide m, define it here, otherwise reuse the base class method
void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};
int main(){
Derived<Base0> d0;
d0.m(); //should print "Derived"
Derived<Base1> d1;
d1.m(); //should print "Base1"
}
With SFINAE, you may do
template<typename T>
struct Derived : public T {
private:
template <typename U = T>
auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }
template <typename U = T>
void m_impl(... ) { std::cout<<"Derived\n"; }
public:
void m() { m_impl(0); }
};
Demo
In order to be general, you should define the function anyway under a different signature:
template<typename T>
struct Derived : public T
{
auto m(std::false_type) { std::cout<<"Derived\n"; }
};
Then you can use the methods given in this thread in order to check whether the base class has the function m():
template <typename...>
using void_t = void;
template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};
template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};
template <typename T>
using has_m = decltype(std::declval<T>().m());
Finally, you can use that as
template<typename T>
struct Derived : public T
{
auto m(std::true_type) { return T::m(); }
auto m(std::false_type) { std::cout<<"Derived\n"; }
auto m() { return m(detect</* const */ T, has_m>{}); }
^^^^^^^^^^
//if m() is const
};
DEMO
As Aslay Berby already said this is probably not the way that you would like to go. If you want to implement something like traits or policy-based design, the following code might be what you are looking for. In fact such designs are used quite commonly and have also idiomatic value.
#include <iostream>
using namespace std;
struct StandardTraits {void foo() {cout << "standard" << endl;}};
struct Traits1 {void foo() {cout << "traits1" << endl;}};
struct Traits2 {void foo() {cout << "traits2"<< endl;}};
template<typename T = StandardTraits>
class SomeClass
{
public:
typedef T Traits;
void useTraits() {traits.foo();}
private:
Traits traits;
};
int main() {
SomeClass<> x;
SomeClass<Traits1> y;
SomeClass<Traits2> z;
x.useTraits();
y.useTraits();
z.useTraits();
return 0;
}
// output:
// standard
// traits1
// traits2
See also: https://en.wikipedia.org/wiki/Policy-based_design

Template method specialization for multiple types

I have a class “A” which exposes the template method foo.
Foo has a standard implementation which works fine with B,C. It also has a special implementation for D.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D>
{
//special implementation
}
}
class B{};
class C{};
class D{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
}
Now, I need to add the class E, which requires for "foo" the same special implementation as D.
Is there a way to say something like: For all the types use the standard foo. For D,E (and so on) the special implementation.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D && E> <-- PseudoCode - It doesn't work
{
//special implementation
}
}
class B{};
class C{};
class D{};
class E{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
A<E> a4;
}
I was thinking to use the trait classes. But I was hoping there is something simpler to achieve this.
Thanks
Using Walter Brown's (C++1z) void_t.
#include <iostream>
#include <type_traits>
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct has_bar
: std::false_type { };
template <typename T>
struct has_bar<T, void_t<decltype( std::declval<T&>().bar() ) > >
: std::true_type { };
class A {
public:
void foo() { };
};
class B {
public:
void bar() { };
};
class C {
public:
void bar() { };
};
template <typename T>
typename std::enable_if<!has_bar<T>::value, void>::type
fun(T t) {
std::cout << "fun" << std::endl;
}
template <typename T>
typename std::enable_if<has_bar<T>::value, void>::type
fun(T t) {
std::cout << "special fun" << std::endl;
}
The code...
int main(const int argc, const char* argv[argc]) {
A a;
B b;
C c;
fun(a);
fun(b);
fun(c);
return 0;
}
prints out
fun
special fun
special fun
Note, that does not check any type semantics, so it may be better declaring bar() as an interface and using std::is_base_of.
You should take a look on SFINAE to enable and disable function at compile time
If D and E are special, they have let's say the member void bar() and not the others, you can actually implement your own type trait:
template<typename T>
struct has_bar {
private:
template<typename C> static std::true_type test(decltype(&C::bar)*);
template<typename C> static std::false_type test(...);
public:
constexpr static bool value = decltype(test<T>(nullptr))::value;
};
/* false */ /* true */
cout << boolalpha << has_bar<A> << " " << has_bar<E> << endl;
Now with this type trait you can use std::enable_if as a compile time switch:
/* standard if no bar */
template<typename T, typename = enable_if_t< !has_bar<T> >>
void foo()
{
//standard implementation
}
/* special if bar */
template<<typename T, typename = enable_if_t< has_bar<T> >>
void foo()
{
//special implementation
}
AFAIK there's no way you can do this without defining some SFINAE machinery. Now the minimum I can think of without including type_traits header would be the following:
Define "home made "enable_if and is_same type traits as follows.
namespace mine {
template<bool, typename T = void> struct enable_if {};
template<typename T> struct enable_if<true, T> { typedef T type; };
template<typename T, typename U> struct is_same { static bool const value = false; };
template<typename T> struct is_same<T, T> { static bool const value = true; };
};
Apply SFINAE in member function foo() of class A as follows:
class A {
template<typename T>
struct pred {
static bool const value = mine::is_same<T, B>::value ||
mine::is_same<T, C>::value || mine::is_same<T, D>::value || mine::is_same<T, E>::value;
};
public:
template<typename T>
typename mine::enable_if< pred<T>::value, void>::type
foo() { std::cout << "special implementation" << std::endl; }
template<typename T>
typename mine::enable_if<!pred<T>::value, void>::type
foo() {std::cout << "standard implementation" << std::endl; }
};
LIVE DEMO
P.S the bonus is that the above solution works also for pre C++11 compilers.

partially specialized template as a trait member type

I want to choose a template from a trait class, like in the following:
template<typename T>
class JobTypeA { };
template<typename T>
class JobTypeB { };
template<typename T>
class JobTraits
{
/* nothing */
};
class A { };
template<>
class JobTraits<A>
{
typedef JobTypeA Type;
};
class B {};
template<>
class JobTraits<B>
{
typedef JobTypeB Type;
};
class JobTarget1 { };
class JobTarget2 { };
template<typename T, typename U>
class JobUser
{
public:
typedef typename JobTraits<T>::Type<U> JobType;
void doSomething (void)
{
JobType j;
/*... */
}
};
int
main (void)
{
JobUser<B, JobTarget1> j;
}
The above wont compile because of the "typedef of an incomplete type" in the specialized traits classes. I got this working using 'alias templates' in std=c++11 with g++ 4.7.2. However VS2010 does not support it yet. Are there any workarounds to achieve the same without 'alias templates'.
How about
template<typename U>
struct Type
{
typedef JobTypeA<U> type;
};
and
template<typename U>
struct Type
{
typedef JobTypeB<U> type;
};
Usage:
typedef typename JobTraits<T>::template Type<U>::type JobType;

Disable functions inside templated class

I'm trying to disable some functions inside a simple template class. The functions that should be removed depend on whether the template argument has certain typedefs.
The example boils down to this:
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
However this gives me a error: no type named ‘Nested’ in ‘struct NoNested’ style error on gcc and clang++ (mind you old versions of both).
Is there an easy way to remove foo when the typedef T::Nested does not exit? (Other than template specialization of the Foo<T> class, as in the real code I have this for about 5 functions with different typedefs.. which would result in 2^5 different specialization )
EDIT:
Since there has been some asking for the motivation for wanting to do this:
I'd like to create something like acompile time FSM for use in a DSL.
I'd like to be able to do this
struct StateA;
struct StateB;
struct StateC;
struct StateA
{
typedef StateB AfterNext;
};
struct StateB
{
typedef StateA AfterPrev;
typedef StateC AfterNext;
};
struct StateC
{
typedef StateB AfterPrev;
};
template<typename T>
struct FSM
{
FSM<typename T::AfterNext> next() { return FSM<T::AfterNext>(); };
FSM<typename T::AfterPrev> prev() { return FSM<T::AfterPrev>(); };
};
So that
FSM<StateA>().next().prev().next().next();
compiles, but
FSM<StateA>().next().prev().prev();
fails.
Note that in reality there would be more transition functions than this, the transition functions would actually do something, and the FSM would store some state.
UPDATE:
I've created proper examples using the methods that have been given so far.
The answers vary in complexity, and while visitors method is the one I'd probably end up using (as it is simplest), my solution (the most complicated) is the only one that actually removes the function.
You can use class template specialization. If you have several functions, then you can move each function to a base class, and specialize each base class.
Try making function foo template itself. It will compile only when called, so you will get the error only when you will try calling it with NoNested class.
You could add a nested typedef to every class, such that compilation only fails when the function is instantiated.
struct null_type; //an incomplete type, you could use a more descriptive name for your particular problem
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
typedef null_type Nested;
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo(); //attempt to use incomplete type when used
fnn.bar();
}
It is possible to choose the type T::Nested, if it exists, otherwise void, as follows.
The default choice is void:
template<class T, class = void>
struct NestedReturn
{
typedef void type;
};
A template which always returns void, whatever type you give it:
template<class T>
struct Void
{
typedef void type;
};
A specialisation for types with a Nested nested class by SFINAE. Note that typename Void<typename T::Nested>::type is always void, to match the default second parameter of void in the base template:
template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
typedef typename T::Nested type;
};
And now we use it. Note that foo() is not actually removed when there is no T::Nested, but instantiating it causes an error.
template<typename T>
struct Foo
{
typename NestedReturn<T>::type foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
I suspect that using default function template parameters it would be possible to remove foo() properly using SFINAE, but that's only possible in C++11 (untested guesswork):
template<typename T>
struct Foo
{
template<class N = T::Nested>
N foo() { return N(); }
int bar() { return 1; }
};
Here's how I think I can solve it. It's inspired by user763305's comments.
It requires 2*N specialisations rather than 2^N.
template <typename T>
struct has_nested {
// Variables "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::Nested*);
template <typename>
static no& test(...);
// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named type.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template<typename T>
struct FooBase
{
int bar() { return 1; }
};
template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};
template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
typename T::Nested foo() { return typename T::Nested(); }
};
template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}