0

Я пытаюсь выяснить, в чем проблема с этим фрагментом кода. В основном type2 наследует от type1<T>, type1<T2>, и я хочу инициализировать член value из одного из базовых классов.C++ Member variable initialization in templated inherited class

#include <utility> 

template <typename T> 
struct type1 { 
    using base_type = T; 

    template <typename... Args> type1(Args&&... args) : value(std::forward<Args>(args)...) {} 

    T value; 
}; 

template <typename... Ts> 
struct type2 : public Ts... { 
    template <typename T> 
    type2(T&& arg) : T::value(std::move(arg.value)) {} 
}; 

int main() 
{ 
    type2<type1<int>, type1<double>> x(type1<int>(10)); 
    return 0; 
} 

Но я получаю следующее сообщение об ошибке с лязгом:

Error(s): 

source_file.cpp:15:25: error: typename specifier refers to non-type member 'value' in 'type1<int>' 
    type2(T&& arg) : T::value(std::move(arg.value)) {} 
         ^~~~~ 
source_file.cpp:20:38: note: in instantiation of function template specialization 'type2<type1<int>, type1<double> >::type2<type1<int> >' requested here 
    type2<type1<int>, type1<double>> x(type1<int>(10)); 
            ^
source_file.cpp:9:7: note: referenced member 'value' is declared here 
    T value; 
    ^
1 error generated. 

Почему лязгом говорят typename specifier refers to non-type member 'value' in 'type1<int>'? Gcc хочет лечить (вероятно, лязг тоже) value как тип:

Error(s): 

source_file.cpp: In instantiation of ‘type2<Ts>::type2(T&&) [with T = type1<int>; Ts = {type1<int>, type1<double>}]’: 
source_file.cpp:20:54: required from here 
source_file.cpp:15:51: error: no type named ‘value’ in ‘struct type1<int>’ 
    type2(T&& arg) : T::value(std::move(arg.value)) {} 
               ^

ответ

1

Вы не можете инициализировать член базового класса в списке конструктора инициализатора.

В Standardese, T::value(std::move(arg.value)) в type2(T&& arg) : T::value(std::move(arg.value)) {} называется MEM-инициализатором и T::value называется MEM-инициализатор идентификатор. По словам [class.base.init]p2, не

Если в MEM-инициализатор-идентификаторе имен класс конструктора, нестатический член данных класса конструктора, или прямая или виртуальная база этого класса, мем-инициализатор плохо сформирован.

Вы можете вызвать конструктор базового класса и дать ему возможность инициализировать элемент. В этом конкретном случае вам нужно только изменить T::value(std::move(arg.value)) на T(std::move(arg.value)). Demo.