Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use a template parameter in a preprocessor directive?

Is it possible to use a non-type constant template parameter in a preprocessor directive? Here's what I have in mind:

template <int DING>
struct Foo
{
    enum { DOO = DING };
};

template <typename T>
struct Blah
{
    void DoIt()
    {
        #if (T::DOO & 0x010)

        // some code here

        #endif
    }
};

When I try this with something like Blah<Foo<0xFFFF>>, VC++ 2010 complains something about unmatched parentheses in the line where we are trying to use #if. I am guessing the preprocessor doesn't really know anything about templates and this sort of thing just isn't in its domain. What say?

like image 670
Raj Avatar asked May 25 '10 12:05

Raj


People also ask

What is a template parameter?

Explanation: A template parameter is a special kind of parameter that can be used to pass a type as argument.

Can we pass Nontype parameters to templates?

Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.

Can a template be a template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

How do you name a template parameter?

If there is just a single template parameter, I name it T (or U,V for nested templates). When there are multiple parameters and the use is not immediately obvious then I use descriptive names prefixed with T. For example, TKey, TValue, TIdentifiier, etc ...


3 Answers

No, this is not possible. The preprocessor is pretty dumb, and it has no knowledge of the structure of your program. If T::Doo is not defined in the preprocessor (and it can't be, because of the ::), it cannot evaluate that expression and will fail.

However, you can rely on the compiler to do the smart thing for you:

        if (T::Doo & 0x010) {
            // some code here
        }

Constant expressions and dead branches are optimized away even at the lower optimization settings, so you can safely do this without any runtime overhead.

like image 157
Thomas Avatar answered Sep 24 '22 03:09

Thomas


what members are available in T depends on which bits are set in T::DOO

It sounds to me like T::DOO is acting like a subclass identifier. So I'm thinking that your Foo and related classes should be subclasses of a class that guarantees that DOO is defined.

The key is: why must you use a bit field?

like image 40
Mike DeSimone Avatar answered Sep 25 '22 03:09

Mike DeSimone


Not sure if this applies to your situation, but it is possible to isolate different cases with template classes. For example: (using a modified version of your code from above)

template <typename T, int N>
struct Blah
{
    void DoIt()
    {
        // normal DoIt() code
    }
};

template <typename T>
struct Blah<T,5>
{
    void DoIt()
    {
        // special DoIt() code for only when N==5
    }
};
like image 42
Chris Avatar answered Sep 25 '22 03:09

Chris