Вопрос

Я пишу простой точечный код, тестируя 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> перегрузка.

Это было полезно?

Решение

Не уверен на 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};
}

Другие советы

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

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, вам необходимо указать его в определении.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top