CRTP не удается с DECTTYPE
-
26-09-2019 - |
Вопрос
template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Кажется, довольно просто для меня. Но MSVC не может компилировать.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Несмотря на то, что компилятор радостно примет, вызывая функцию. Приведенный ниже образца компилируется нормально.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
У меня такая же проблема, пытающаяся использовать любые типы из аргумента шаблона.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Тогда как класс B четко определяет тип называемый «что-то». Компилятор идеально рад вызывать функции на объекте типа T, T & или T *, но я не могу получить доступ к любым типам из T.
Решение
Вы пытаетесь использовать T::func
до того, как он был объявлен. Вот почему компилятор кричит на вас. Обратите внимание, что когда вы получаете из класса, класс генерируется, если он исходит от шаблона класса. И неявное поколение класса (которое называется неявной инстанцией) требует генерации деклараций для всех его членов (поэтому компилятор знает значение в размере класса и может выполнить поиск в него).
Так что это также создает признательности декларации auto func() -> decltype(T::func())
И наверняка не удается здесь.
Другие советы
Кажется, есть несколько проблем с вашим кодом, один из которых выглядит как ошибка VS10.
- Вы звонили
T::func()
отA
без литьяA
кT
, это необходимо как часть CRPT с моментаA
не происходит отT
. Отказ - fixl.return static_cast<T*>(this)->func();
- Чем вы передаете
decltype
выглядит как статическая вызов функции в то время какfunc
на самом деле функция экземпляра. Сdecltype
нет на самом деле запустить функцию, которую вы должны сделать что-то вроде этогоdecltype(static_cast<T*>(nullptr)->func())
func
является частным вB
и не может быть вызван отA
- Исправить: изменитьA
бытьstruct
- Это похоже на ошибку в VS10, даже после всех этих исправлений я получаю ошибку, которую вы пытаетесь использовать неопределенный класс
B
вdecltype
.
Как обходной путь вы можете рефакторировать func
в базовый класс? (Теперь нам нужны два параметра шаблона, один для литья до одного для decltype
Таким образом, создание нового IDIOM CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
Я вижу, что G ++ также задыхается на этом decltype
Может кто-нибудь подтвердить, что это дефект? Если так, я открою ошибку для Microsoft. Я понимаю, что следующий код действителен, но ни G ++, ни VC10 не компилируют его.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
Во-первых, я думаю, что код рядом - правильный:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
Как отметил Мотти. Однако это Все еще не удается, и я думаю по причине, что возвратный тип базы должен быть известен, когда B
наследуется от A<B>
, но с тех пор B
Это еще не определено, это становится проблемой курицы и яйца.
Тем не менее, может быть, наконец возможен в C++1y
Используя просто auto
(без decltype
), Я пытался с gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
Это компилирует (c++ -std=c++1y
) и работает:
int main(){
B b; b.func();
}
Два отказ от ответственности: я не знаю, почему это работает. Я не знаю, насколько это стандартно.