C++11 Initialization of template class member in template class

I have a bunch of template classes, based on an enumeration type. Here is the source code:

#include <iostream> // An enum type enum class ENUMR : unsigned char { SYSTEM1, SYSTEM2, UNKNOWN }; // template class; will later be specialized based on ENUMR enumerators template<ENUMR S> class System {}; // specialized System class, for enumerator SYSTEM1 template<> class System<ENUMR::SYSTEM1> { private: static constexpr char identifier { 'G' }; }; // An observation class recorded from a certain System instance template<ENUMR Sys,short int Freq> class Obs { public: Obs(): m_system {System<Sys> {} }, // does not work m_frequency {Freq} {}; //{ // m_system = System<Sys> {}; // works //} private: System<Sys> m_system; short int m_frequency; }; // dummy code to test the template classes int main () { System<ENUMR::SYSTEM1> s1; System<ENUMR::UNKNOWN> s2; System<ENUMR::SYSTEM1> s3 (System<ENUMR::SYSTEM1>); Obs<ENUMR::SYSTEM1, 1> obs; std::cout <<"\n"; return 0; }

Initialization of the member (template) variable Obs::m_system produces a compile-time error, when performed as m_system {System<Sys> {} }. However, when the same variable is initialized as m_system = System<Sys> {}; the source codes gets compiled (the respective lines in the source code above are commented). Does that mean that the assignment operator works, but the copy constructor fails? If so, why? When compiled against the gcc version 4.8.3 i get the following error message:

test.cpp: In instantiation of ‘Obs<Sys, Freq>::Obs() [with ENUMR Sys = (ENUMR)0u; short int Freq = 1]’: test.cpp:43:28: required from here test.cpp:25:22: error: too many initializers for ‘System<(ENUMR)0u>’ m_frequency {Freq} {};

-------------Problems Reply------------

System<ENUMR::SYSTEM1> is an aggregate, so the mem-initializer m_system { System<Sys>{} } performs aggregate-initialization. Since System<ENUMR::SYSTEM1> has no corresponding member - indeed it has no members at all - for the corresponding initializer System<Sys>{}, you get the error indicating there are too many initializers.

If System<ENUMR::SYSTEM1> were not an aggregate, the effect of that mem-initializer would be to direct-list-initialize m_system from a value-initialized temporary of the same type. Since the move/copy constructors are defaulted, you could achieve the equivalent effect for both the aggregate and non-aggregate case by directly value-initializing m_system with an empty brace initializer: m_system {}. (DEMO)

If you change

m_system{ System<Sys>{} },
m_frequency{ Freq }

to

m_system( System<Sys>{} ),
m_frequency( Freq )

it will compile. Note however, that the first initializer creates a default constructed temporary, and then uses the copy constructor to initialize the member. Since you want m_system to be default constructed, that initializer can be omitted.

Category:templates Views:0 Time:2017-09-11

Related post

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.251 (s). 10 q(s)