Использовать параметр шаблона в директиве препроцессора?

Можно ли использовать параметр шаблона константы нетипового типа в директиве препроцессора? Вот что я имею в виду:

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

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

        // some code here

        #endif
    }
};

Когда я пробую это с чем-то вроде Blah<Foo<0xFFFF>>, VC++ 2010 жалуется на несовпадающие круглые скобки в строке, где мы пытаемся использовать #if. Я предполагаю, что препроцессор на самом деле ничего не знает о шаблонах, и такие вещи просто не в его области. Что сказать?


person Raj    schedule 25.05.2010    source источник
comment
Просто обратите внимание: Blah<Foo<0xFFFF>> не будет анализироваться в текущем С++, вам нужен пробел между >. Blah<Foo<0xFFFF> >.   -  person KitsuneYMG    schedule 25.05.2010
comment
На самом деле, в VC++ 2010 он компилируется! :) Они частично реализовали C++0x в VC++ 2010.   -  person Raj    schedule 25.05.2010


Ответы (3)


Нет, это невозможно. Препроцессор довольно тупой и не знает структуры вашей программы. Если T::Doo не определено в препроцессоре (а этого не может быть из-за ::), он не сможет вычислить это выражение и завершится ошибкой.

Однако вы можете положиться на то, что компилятор сделает все за вас:

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

Константные выражения и мертвые ветки оптимизируются даже при более низких настройках оптимизации, поэтому вы можете безопасно делать это без каких-либо накладных расходов во время выполнения.

person Thomas    schedule 25.05.2010
comment
Не скомпилируется ли это, если Doo отсутствует в T? - person Michael Kristofik; 25.05.2010
comment
Спасибо. Это то, о чем я думал. Однако использование компилятора не идеально для меня, потому что то, какие элементы доступны в T, зависит от того, какие биты установлены в T::DOO. Я уверен, что подхожу к этому неправильно. Я придумаю что-нибудь еще. Но мне просто любопытно, как далеко мы можем зайти с препроцессором. Другой вариант может заключаться в том, чтобы посмотреть, можно ли использовать для этого приемы метапрограммирования шаблонов. - person Raj; 25.05.2010
comment
Наверное, могут. Если вы откроете новый вопрос с подробностями того, чего вы хотите достичь, мы можем посмотреть. - person Thomas; 25.05.2010

какие элементы доступны в T, зависит от того, какие биты установлены в T::DOO

Мне кажется, что T::DOO действует как идентификатор подкласса. Поэтому я думаю, что ваш Foo и связанные с ним классы должны быть подклассами класса, который гарантирует, что DOO определено.

Ключ в том, почему вы должны использовать битовое поле?

person Mike DeSimone    schedule 25.05.2010
comment
Ответ на этот вопрос немного сложен, но вы совершенно правы. Я работаю с этим API (DirectX), который обеспечивает определенную гибкость при указании того, как вы хотите форматировать содержимое определенной структуры, которая передается в качестве входных данных для одного из ее методов. Информация о том, как у вас настроена структура, передается через битовое поле. В моем приложении у меня есть 2 абстракции: первая — это класс шаблона, который генерирует коллекцию экземпляров этой структуры с битовым полем и самой структурой, передаваемой в качестве аргументов шаблона, а другой — потребляет эту коллекцию. Комментарий продолжение ниже - person Raj; 25.05.2010
comment
Я хотел написать некоторый условный код в потребительском классе, который использовал бы определенные члены этой структуры, проверяя, какие биты установлены в битовом поле. Фу! Я не уверен, насколько это имело смысл! Поскольку существуют различные экземпляры шаблона исходного класса, сопоставленные с различными вариантами структуры, рассматриваемый код должен быть условно скомпилирован — отсюда и идея попытаться увидеть, можно ли использовать препроцессор. - person Raj; 25.05.2010

Не уверен, что это относится к вашей ситуации, но можно изолировать разные случаи с помощью классов шаблонов. Например: (используя модифицированную версию вашего кода сверху)

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
    }
};
person Chris    schedule 03.09.2010