Question

Given this template:

template <class A>
struct Something {
    ... // members common to all template instantiations for all A types 
    SpecialType member; // but not this - I want this to be conditional...
}

...I want to use "enable_if" to have the SpecialType member exist conditionally; that is, only when the template is instantiated with A=SpecialCase1 or SpecialCase2 types. In all other cases, I want the SpecialType member to be missing.

In case you're wondering why, this is about optimization - i.e. not carrying useless payload in the struct. I am a newbie in template metaprogramming, but I understand I need "enable_if" and two "is_same" somehow - not sure exactly how, though...

EDIT: Doing it with generic C++ (i.e. without Boost-specifics) would be a plus.

Was it helpful?

Solution

Well: use a base class.

struct Empty {};

struct SpecialTypeCnt { SpecialType member; };

template <typename A>
struct Something: if_< /* cond */ , SpecialTypeCnt, Empty>::type {
};

Where if_ is defined as:

template <typename, typename, typename E> struct if_ { typedef E type; };

template <typename T, typename E>
struct if_<std::true_type, T, E> { typedef T type; };

(You can also specialize on a boolean)

Now of course, you need to express your condition properly.


Having said that, you should probably not use just a struct. Instead you should use a class which provides the operations that need be applied on member. Then you provide a class Null with a default behavior and a class SomeType with the behavior specific to member.

Otherwise you'll rewrite the condition everywhere you need to "perhaps" modify member, and it gets annoying real quick.

OTHER TIPS

You don't need enable_if for this. Specialize your struct for special cases and leave the default implementation for the rest:

template <class A>
struct Something
{
  // your default implementation
};

template <>
struct Something<SpecialCase1>
{
  // your SpecialCase1 implementation
};

template <>
struct Something<SpecialCase2>
{
  // your SpecialCase2 implementation
};

In order not to duplicate common members:

Define BaseSomething class:

 template <class A>
        struct BaseSomething {
            ... // members common to all template instantiations for all A types 
                };

Define SpecialSomething class:

template <class A>
            struct SpecialSomething {
                SpecialType member;
                ...//SpetialType related functionality
                    };

Define Something class:

template <class A>
            struct Something :public BaseSomething<A>{

                    };



  template<>
    struct Something<SpecialCase1>:public BaseSomething<A>{
                    SpecialSomething<SpecialCase1> special;
                        };


template<>
struct Something<SpecialCase2>:public BaseSomething<A>{
                SpecialSomething<SpecialCase2> special;
                    };

This has already been answered by Matthieu M. However, a slightly more idoimatic and elegant solution would be to do the following:

struct OptionalMembers { SpecialType member; };

template <typename T>
    class Something: public conditional_t<is_same<T, SpecialCase>, OptionalMembers, tuple<>> {
};

This example shows how to add optional members only when template parameter is of type SpecialCase.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top