Я пытаюсь исправить странную ошибку, которую я имею с этим кодом. Это минимальный пример, который может повторить ошибку:
test11.cpp
:
namespace detail{
template <auto UInt>
class Test{
public:
typedef decltype(UInt) value_type;
Test (const value_type& x = 0);
protected:
value_type n;
};
template<auto UInt>
Test<UInt>::Test (const value_type& x) : n(x){}
// Here, void would be substitute with some enable_if stuff
template <auto UInt, typename = void>
class TestChild : public Test<UInt>{
public:
typedef typename Test<UInt>::value_type value_type;
TestChild (const value_type& x = 0);
value_type foo() const;
};
template<auto UInt>
TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}
template<auto UInt>
value_type TestChild<UInt>::foo(){
value_type ret=42;
return ret;
}
}
int main(){}
Я скомпилировал его, используя GCC 7.2.0 и Clang 5.0.0 в Ubuntu 16.04 LTS. Вы можете увидеть эти две ссылки для демонстраций:
Это сообщение об ошибке в gcc:
test11.cpp:27:38: error: ‘value_type’ does not name a type
TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}
^~~~~~~~~~
test11.cpp:27:51: error: invalid use of incomplete type ‘class detail::TestChild<UInt>’
TestChild<UInt>::TestChild (const value_type& x) : Test<UInt>(x){}
^
test11.cpp:18:10: note: declaration of ‘class detail::TestChild<UInt>’
class TestChild : public Test<UInt>{
^~~~~~~~~
test11.cpp:30:4: error: ‘value_type’ does not name a type
value_type TestChild<UInt>::foo(){
^~~~~~~~~~
Кроме того, что действительно странно для меня, так это то, что, если я опущу фиктивный параметр в шаблоне для класса TestChild
(Я имею в виду, template<auto UInt>
вместо template<auto UInt, typename = void>
), Я все еще получаю (более короткую) ошибку, которая выглядит так:
test11.cpp:30:4: error: ‘value_type’ does not name a type
value_type TestChild<UInt>::foo(){
^~~~~~~~~~
Вы можете проверить демо для GCC 7.2.0 Вот.
Похоже, главная ошибка в том, что, если я определяю функции вне класса, typedef typename Test<UInt>::value_type value_type;
на самом деле не обнаружено (не знаю, хорошо ли я объяснил).
Это будет иметь смысл для меня, если это также произойдет, когда я определю функции внутри класса, но это не так, потому что в последнем случае все прекрасно компилируется (вы можете увидеть это в демонстрация если хотите).
В заключение, мой главный вопрос заключается в том, что я хочу скомпилировать эту программу, но с учетом того, что я должен отделить декларацию от определения. Итак, последняя демонстрация, которую я показал (где все определено внутри класса) — это то, чего я хочу достичь, но модульность.
Я надеюсь, что кто-то может мне помочь и объяснить, что происходит с этим кодом.
Вы должны сделать три (как минимум) изменения.
Первый: добавьте второе (по умолчанию) значение шаблона для TestChild
,
Так
//................vvvvvvvvvvvv
template<auto UInt, typename V>
TestChild<UInt, V>::TestChild (const value_type& x) : Test<UInt>(x){}
//............^^^
и то же самое для foo()
метод
Второе: запомни это foo()
является const
Так
template <auto UInt, typename V>
value_type TestChild<UInt, V>::foo() const {
value_type ret=42; // ...........^^^^^
return ret;
}
В-третьих: для типа возврата для foo()
явный класс
Так typename TestChild<UInt, V>::value_type
вместо value_type
template <auto UInt, typename V>
typename TestChild<UInt, V>::value_type TestChild<UInt, V>::foo() const {
value_type ret=42;
return ret;
}
Или, если вы предпочитаете, вы можете использовать auto ... ->
синтаксис возвращаемого типа
template<auto UInt, typename V>
auto TestChild<UInt, V>::foo() const -> value_type {
value_type ret=42;
return ret;
}
или просто auto
(но также в объявлении метода)
auto foo() const;
// ...
template<auto UInt, typename V>
auto TestChild<UInt, V>::foo() const {
value_type ret=42;
return ret;
}
Других решений пока нет …