Как предотвратить создание экземпляра метода класса шаблона C ++ при выполнении определенного условия? - PullRequest
6 голосов
/ 28 ноября 2010

В настоящее время я пишу универсальный векторный шаблон класса (геометрический объект, а не контейнер) со следующей сигнатурой ...


template&lt typename T, unsigned N &gt
class vector
{...}

... где T - арифметический тип, а N,измерение.Я хотел бы определить перекрестный продукт как перегрузку оператора ^ (находится внутри определения класса) и включить его только тогда, когда N == 3. Теперь у меня есть:


typename boost::lazy_enable_if_c&lt (N == 3), vector &gt::type
inline operator ^(const vector &rhs) const
{
    vector ret;
    ret(0) = val_[1] * rhs(2) - val_[2] * rhs(1);
    ret(1) = val_[2] * rhs(0) - val_[0] * rhs(2);
    ret(2) = val_[0] * rhs(1) - val_[1] * rhs(0);
    return ret;
}

К сожалению, создание экземпляраэтот шаблон с N! = 3, хотя оператор ^ не указан, выдает следующую ошибку:


error: no type named ‘type’ in ‘struct boost::lazy_enable_if_c &lt false, flare::math::vector &lt flare::math::fixed &lt short int, 8u &gt, 2u &gt &gt’

Что я делаю не так?Есть ли альтернатива boost :: enable_if в таком случае?

Большое спасибо.

Ответы [ 2 ]

4 голосов
/ 28 ноября 2010

Проксимальная причина сообщения об ошибке заключается в том, что, согласно документам , "второй аргумент lazy_enable_if должен быть типом класса, который определяет вложенный тип с именем type всякий раз, когда первый параметр (условие) верно ". Это явно не устраивает (если только ваш тип vector не содержит typedef something type;).

Вам не нужно lazy_... здесь. Согласно документации, это необходимо, только если 2-й аргумент может быть неопределенным (например, если 2-й аргумент был typename foo<T>::bar, а тип bar определен не для всех типов T). vector (что здесь означает vector<T, N>) всегда будет определяться.

Так что определенно попытайтесь избавиться от lazy_, или в качестве альтернативы создайте класс черт бездействия template <typename T> struct nop { typedef T type; }; и замените 2-й аргумент на lazy_enable_if_c на nop<vector>. Но я думаю, вы уже пробовали первое, по крайней мере. :)

И теперь я понимаю, почему это не сработает. Согласно стандарту 14.7.1 / 1:

Если только шаблон класса специализация была явно экземпляр (14.7.2) или явно специализированный (14.7.3), класс специализация шаблона неявно инстанцируется, когда специализация упоминается в контексте, который требует полностью определенного объекта типа или когда полнота Тип класса влияет на семантику программа. Неявный создание шаблона класса специализация вызывает неявное создание деклараций, но не из определений или по умолчанию аргументы члена класса функции, классы-члены, статические данные элементы и шаблоны участников;

Таким образом, все, что вызывает создание экземпляра класса, будет пытаться создавать объявления для всех методов, которые завершатся неудачно, когда N != 3. Похоже, вам нужно использовать всегда присутствующий метод, который вместо этого передает шаблон функции. Не волнуйтесь, любой приличный компилятор все еще сможет встроить это:

template< typename T, unsigned N > class vector;   // Fwd decl.

template< typename T, unsigned N >
inline boost::enable_if_c< (N == 3), vector<T, N> >::type
magic(const vector<T, N>& lhs, const vector<T, N>& rhs) {
    /* Do the calculation as before... */
    return ret;
}

template< typename T, unsigned N >
class vector {
    ...
    inline vector operator ^(const vector &rhs) const {
        return magic(*this, rhs);
    }
};

Это будет работать, потому что функция-член определений не создается, если они не были фактически вызваны (или их адреса не получены)

2 голосов
/ 28 ноября 2010

Я считаю, что ваша проблема "находится внутри определения класса". Я думаю, что у вас будет меньше проблем, если вы перегрузите оператор с помощью функции, а не с помощью метода.

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

...