to zależy od sposobu korzystania z nich stałe wyrażenia.
ODR (zasada jednej definicji) stanowi
(§3.2/2) [...] Zmienna którego nazwa pojawia się jako potencjalnie z wyrażenia jest ODR wykorzystane, o ile nie jest obiekt, który spełnia wymagania dotyczące pojawiania się w stałym wyrażeniu (5.19), a konwersja l-wartość-r (4.1) jest natychmiast stosowana. [...]
(A potem, wiele specjalnych zasad, wyjątków i odstępstw od wyjątków naśladowania.)
Każda zmienna jest ODR-używany, musi mieć dokładnie jedną definicję. Twoje stałe wyrażenia mają deklarację, ale nie definicję, więc to dobrze, chyba że użyjesz odr z jednego z nich.
Na przykład, następujący idzie dobrze:
int main() {
E e = GetE<float>::type;
return 0;
}
Ale tego nie robi:
void f(const E &)
{ }
int main() {
f(GetE<float>::type);
return 0;
}
ponieważ f
wymaga (const) referencję, więc RValue lwartość do konwersji nie może być zastosowane natychmiast, a więc stanowi to użycie odr. Kompilator będzie skarżył się, że pomija definicję.
(Uwaga: jak stwierdził ShafikYaghmour (patrz komentarze), możesz nie otrzymać skargi, jeśli kompilator używa optymalizacji, ponieważ referencje mogą zostać zoptymalizowane z dala. Aby odtworzyć skargę kompilatora, użyj flagi -O0
(lub podobnej, w zależności od kompilatora).)
Aby rozwiązać problem, wymaganą definicję można podać w zwykły sposób, tj.poza struct rozdzielczości:
constexpr E GetE<float>::type;
constexpr E GetE<char>::type;
constexpr E GetE<int>::type;
Ale ponieważ to musiałoby się wydarzyć w .cpp (nie pliku nagłówka), będziesz skończyć się koniecznością utrzymania deklaracje i definicje w dwóch różnych miejscach, co jest niewygodny.
roztworze właśnie zasugerował w swoim komentarzu, to znaczy określić constexpr (inline) oraz funkcji, dźwięków prawej:
template <class T> constexpr E GetE();
template <> constexpr E GetE<float>()
{ return TYPE_FLOAT; }
template <> constexpr E GetE<char>()
{ return TYPE_CHAR; }
template <> constexpr E GetE<int>()
{ return TYPE_INT; }
void f(const E &)
{ }
int main() {
E e = GetE<float>();
f(GetE<float>());
return 0;
}
Tak, to brzmi rozsądnie. Zmieniłem używanie szablonu funkcji, takiego jak 'tmpl E GetE()', a następnie specjalizowałem się, że zamiast tego to naprawiło. Dzięki. –
@jogojapan Próbuję się nauczyć z twojego komentarza, ale nie widzę błędu przy użyciu ostatniego fragmentu kodu: http://liveworkspace.org/code/4oTEis Czego mi brakuje? Dziękujemy –
@ShafikYaghmour Jest to spowodowane flagą kompilatora '-O2'. Optymalizuje odniesienia od siebie. Dobry komentarz, jednak wspomnę o tym w odpowiedzi. – jogojapan