Lubię używać klas lokalnych w klasach szablonów do wykonywania konstrukcji takich jak "statyczne, jeśli". Ale stanąłem przed problemem, że gcc 4.8 nie chce skompilować mojego kodu. Jednak 4.7 to.C++ GCC Dlaczego ten kod sfinae może być skompilowany z GCC 4.7, ale nie z 4.8?
Próbka:
#include <type_traits>
#include <iostream>
#include <string>
using namespace std;
struct A {
void printA() {
cout << "I am A" << endl;
}
};
struct B {
void printB() {
cout << "I am B" << endl;
}
};
template <typename T>
struct Test {
void print() {
struct IfA {
constexpr IfA(T &value) : value(value) {
}
T &value;
void print() {
value.printA();
}
};
struct IfB {
constexpr IfB(T &value) : value(value) {
}
T &value;
void print() {
value.printB();
}
};
struct Else {
constexpr Else(...) {}
void print() {
}
};
typename conditional<is_same<T, A>::value, IfA, Else>::type(value).print();
typename conditional<is_same<T, B>::value, IfB, Else>::type(value).print();
}
T value;
};
int main() {
Test<A>().print();
Test<B>().print();
}
Opcje:
g++ --std=c++11 main.cc -o local-sfinae
Zadanie:
- Biorąc Klasy A i B z różnymi interfejsami do druku.
- Napisz ogólny test, który może drukować zarówno A, jak i B.
- Nie zanieczyszczaj żadnej przestrzeni nazw ani zakresu klasy.
Opis kodu:
- To tylko czysty przykład.
- Używam takiego podejścia, ponieważ chcę generalizować konstrukcję "static if". Zobacz, że przekazuję argumenty do klas IfA i IfB za pośrednictwem ich pól, a nie bezpośrednio do funkcji print().
- Bardzo często stosuję takie konstrukcje.
- Zauważyłem, że te konstrukcje nie powinny znajdować się w zasięgu (zanieczyszczającym) klasy. Mam na myśli, że powinny one być umieszczone w zakresie metody.
Więc pytanie.
Tego kodu nie można skompilować za pomocą GCC 4.8. Ponieważ sprawdza WSZYSTKIE klasy, nawet jeśli nigdy nie są używane. Ale nie tworzy ich w systemie binarnym (skomentowałem linie, które powodują błędy i skompilowałem je za pomocą gcc 4.8). Dowód:
$ nm local-sfinae |c++filt |grep "::If.*print"
0000000000400724 W Test<A>::print()::IfA::print()
00000000004007fe W Test<B>::print()::IfB::print()
Zobacz, nie ma testu :: print() :: IfB :: print(). (Patrz dalej: 'void test :: print() :: IFB :: print() [z T = A]')
błędów jeśli skompilować wspomniany kod z gcc 4.8:
g++ --std=c++11 main.cc -o local-sfinae
main.cc: In instantiation of 'void Test<T>::print()::IfB::print() [with T = A]':
main.cc:36:9: required from 'void Test<T>::print() [with T = A]'
main.cc:49:21: required from here
main.cc:34:17: error: 'struct A' has no member named 'printB'
value.printB();
^
main.cc: In instantiation of 'void Test<T>::print()::IfA::print() [with T = B]':
main.cc:28:9: required from 'void Test<T>::print() [with T = B]'
main.cc:50:21: required from here
main.cc:26:17: error: 'struct B' has no member named 'printA'
value.printA();
^
- Czy jest to błąd GCC 4.8?
- Czy to błąd GCC 4.7? Może kod nie powinien być kompilowany.
- Albo to jest mój błąd, a ja nie powinienem polegać na zachowaniu kompilatora/nie powinienem stosować takiego podejścia do implementacji "static if".
Dodatkowe informacje:
Ten prosty kod kompiluje się na 4.7, ale nie na 4,8. Skróciłem to.
struct A {
void exist() {
}
};
template <typename T>
struct Test {
void print() {
struct LocalClass {
constexpr LocalClass(T &value) : value(value) {
}
T &value;
void print() {
value.notExist();
}
};
}
T value;
};
int main() {
Test<A>().print();
}
Błędy:
main.cc: In instantiation of 'void Test<T>::print()::LocalClass::print() [with T = A]':
main.cc:16:9: required from 'void Test<T>::print() [with T = A]'
main.cc:22:21: required from here
main.cc:14:17: error: 'struct A' has no member named 'notExist'
value.notExist();
^
testowałem dwie wersje GCC 4.8: 2012.10 i 2013.02. Mam nadzieję, że jest to błąd GCC 4.8 i można go naprawić.
źle sformułowany kod o tym, jaki standard mówi, że "brak diagnostyki wymaganej" jest nadal nieważny. Kompilator może więc odmówić skompilowania go. –