Почему СФИНАЕ к этому не относится? - PullRequest
4 голосов
/ 22 октября 2009

При написании Visual Studio 10 (бета-версия 2) я пишу какой-то простой точечный код, и я попал в этот код, где я ожидал, что SFINAE заработает, но, похоже, нет:

template<typename T>
struct point {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

template<typename T, typename U>
struct op_div {
    typedef decltype(T() / U()) type;
};

template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, point<U> const& r) {
    return point<typename op_div<T, U>::type>(l.x / r.x, l.y / r.y);
}

template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, U const& r) {
    return point<typename op_div<T, U>::type>(l.x / r, l.y / r);
}

int main() {
    point<int>(0, 1) / point<float>(2, 3);
}

Это дает error C2512: 'point<T>::point' : no appropriate default constructor available

Учитывая, что это бета-версия, я быстро проверил работоспособность с помощью онлайн-компилятора comeau, и он согласился с идентичной ошибкой, поэтому кажется, что это правильное поведение, но я не понимаю, почему.

В этом случае некоторые обходные пути - просто встроить decltype(T() / U()), присвоить классу точки конструктор по умолчанию или использовать decltype для полного выражения результата, но я получил эту ошибку, пытаясь упростить полученную ошибку. с версией op_div, для которой не требовался конструктор по умолчанию *, поэтому я бы скорее исправил свое понимание C ++, чем просто делал то, что работает.

Спасибо!


*: оригинал:

template<typename T, typename U>
struct op_div {
    static T t(); static U u();
    typedef decltype(t() / u()) type;
};

Что дает error C2784: 'point<op_div<T,U>::type> operator /(const point<T> &,const U &)' : could not deduce template argument for 'const point<T> &' from 'int', а также для перегрузки point<T> / point<U>.

Ответы [ 2 ]

2 голосов
/ 22 октября 2009

Не уверен на 100%. Похоже, что компилятору нужно создать экземпляр обеих перегрузок, чтобы определить, что лучше, но при попытке создать экземпляр другого op_div с помощью T = int и U = point<float> это приводит к ошибке, которая не покрывается SFINAE (ошибка не op_div не имеет типа в этом случае, но этот тип не может быть определен).

Вы можете попытаться отключить вторую перегрузку, если второй тип является точкой (boost::disable_if).

Кроме того, похоже, что работает отложенное объявление возвращаемого типа (отказ от структуры op_div, но в зависимости от того, какие функции C ++ 0x поддерживаются вашим компилятором):

template<typename T, typename U>
auto
operator/(point<T> const& l, point<U> const& r) -> point<decltype(l.x / r.x)> {
    return {l.x / r.x, l.y / r.y};
}

template<typename T, typename U>
auto
operator/(point<T> const& l, U const& r) -> point<decltype(l.x / r)> {
    return {l.x / r, l.y / r};
}
0 голосов
/ 22 октября 2009

Я бы сказал, что ваша ошибка здесь:

template<typename T>
struct point {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

Измените определение структуры следующим образом:

template<typename T>
struct point<T> {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

Если вы хотите использовать универсальный тип T, вам нужно указать его в определении.

...