Domanda

Sto scrivendo un semplice codice punto mentre provo Visual Studio 10 (Beta 2) e ho colpito questo codice dove mi sarei aspettato che SFINAE iniziasse, ma sembra non farlo:

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);
}

Questo dà error C2512: 'point<T>::point' : no appropriate default constructor available

Dato che si tratta di una beta, ho fatto un rapido controllo di integrità con il compilatore comeau online e concorda con un errore identico, quindi sembra che questo comportamento sia corretto, ma non riesco a capire perché.

In questo caso alcune soluzioni alternative consistono semplicemente nell'integrare decltype(T() / U()), per assegnare alla classe punto un costruttore predefinito o per utilizzare il decltype sull'espressione del risultato completo, ma ho riscontrato questo errore mentre cercavo di semplificare un errore che stavo ottenendo con una versione di op_div che non richiedeva un costruttore predefinito *, quindi preferirei correggere la mia comprensione del C ++ piuttosto che fare semplicemente ciò che funziona.

Grazie!


*: l'originale:

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

Che dà 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', e anche per il point<T> / point<U> sovraccarico.

È stato utile?

Soluzione

Non sicuro al 100%. Sembra che il compilatore debba istanziare entrambi i sovraccarichi per determinare quale sia meglio, ma mentre si tenta di istanziare l'altro op_div con T = int e U = point<float>, questo porta a un errore che non è coperto da SFINAE (l'errore non è quello op_div non ha tipo in questo caso, ma quel tipo non può essere determinato).

Potresti provare a disabilitare il secondo sovraccarico se il secondo tipo è un punto (boost::disable_if).

Inoltre, ciò che sembra funzionare è la dichiarazione del tipo di ritorno rinviata (eliminando la struttura op_div, ma a seconda delle funzionalità C ++ 0x supportate dal compilatore):

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};
}

Altri suggerimenti

Direi che il tuo errore è qui:

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

Cambia la definizione della struttura in questa:

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

Se si desidera utilizzare un tipo T generico, è necessario specificarlo nella definizione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top