Thread: Class member initialization

  1. #1
    Registered User
    Join Date
    Jun 2014
    Posts
    66

    Class member initialization

    Hi,

    I've just figured out something I find quite astonishing:

    Code:
    struct base {
        base(std::string label);
    };
    
    
    struct type {
        type()=default; // makes errors below vanish
        type(std::size_t value);
    };
    
    
    int main()
    {
        struct first: base {
            first(std::string label);
            
            type member{0};
        } first{"first"}; // successful compilation
        
        struct second: base {
            using base::base;
        } second{"second"}; // successful compilation
        
        struct third: base {
            using base::base;
            
            type member{0};
        } third{"third"}; // compilation failure if `type::type()' isn't defined
    }
    As you can see, inheriting the base constructor doesn't work when having defined a member variable of custom type. The interesting part is that the reason for this seems to be the initialization process of this variable.

    Simplified compiler output:
    - error: use of deleted function `third::third(std::string)'
    - note: `third::third(std::string)' is implicitly deleted because the default definition would be ill-formed
    - error: no matching function for call to `type::type()'

    How can this happen? Why does the third class try to default-initialize the member variable? I'd be grateful for answers!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Instead of posting "simplified compiler output", post the smallest and simplest program that you expect should compile but which results in a compile/link error, and then post the error messages too. Since the program is expected to compile (and link), you should #include whatever are the relevant headers and define whatever functions need to be defined.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    Sorry, I just wanted to demonstrate what I want to do. Hope this helps:

    Code:
    #include <cstddef>
    #include <string>
    
    
    struct base {
        base(std::string label) {}
    };
     
     
    struct type {
        type(std::size_t value) {}
    };
     
     
    int main()
    {
        struct object: base {
            using base::base;
            
            type member{0};
        } object{"object"};
    }
    Code:
    test.cc: In function ‘int main()’:
    test.cc:20:20: error: use of deleted function ‘main()::third::third(std::string)’
         } third{"third"};
                        ^
    test.cc:17:21: note: ‘main()::third::third(std::string)’ is implicitly deleted because the default definition would be ill-formed:
             using base::base;
                         ^
    test.cc:17:21: error: no matching function for call to ‘type::type()’
    test.cc:10:5: note: candidate: type::type(std::size_t)
         type(std::size_t value);
         ^
    test.cc:10:5: note:   candidate expects 1 argument, 0 provided
    test.cc:9:8: note: candidate: constexpr type::type(const type&)
     struct type {
            ^
    test.cc:9:8: note:   candidate expects 1 argument, 0 provided
    test.cc:9:8: note: candidate: constexpr type::type(type&&)
    test.cc:9:8: note:   candidate expects 1 argument, 0 provided
    What I don't understand is how the switch from a custom constructor to a inherited one can change member initialization when both do the same thing?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Hmm... checking the C++ standard:
    Quote Originally Posted by C++11 Clause 12.9 Paragraph 8 (part)
    An implicitly-defined inheriting constructor performs the set of initializations of the class that would be performed by a user-written inline constructor for that class with a mem-initializer-list whose only mem-initializer has a mem-initializer-id that names the base class denoted in the nested-name-specifier of the using-declaration and an expression-list as specified below, and where the compound-statement in its function body is empty. If that user-written constructor would be ill-formed, the program is ill-formed. Each expression in the expression-list is of the form static_cast<T&&>(p), where p is the name of the corresponding constructor parameter and T is the declared type of p.
    If my interpretation is correct, that means this:
    Code:
    struct object: base {
        using base::base;
    
        type member{0};
    };
    is equivalent to:
    Code:
    struct object: base {
        object(std::string label) : base(static_cast<std::string&&>(label)) {}
    
        type member{0};
    };
    However, it looks like the compiler is treating it as equivalent to:
    Code:
    struct object: base {
        object(std::string label) : base(static_cast<std::string&&>(label)), member() {}
    
        type member{0};
    };
    in which case you get an error because the value initialisation of member in the member initialiser list supersedes the initialisation of member to 0 at the class definition level, but the class named type has no default constructor.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    Could that mean it is a compiler-specific issue? I've just tried out clang - the same code compiled and linked without complaints!

    Code:
    $ g++ --version
    
    g++ (GCC) 5.2.0
    Copyright (C) 2015 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    Code:
    $ clang++ --version
    
    clang version 3.7.0 (tags/RELEASE_370/final)
    Target: x86_64-unknown-linux-gnu
    Thread model: posix

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Based on my interpretation of the text of C++11 (and C++14 apparently retains the same text), it is a compiler bug.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    Okay, I'll try to build the current development version of GCC the next few days and see if the problem is fixed, otherwise I'll have a look at bugzilla. Thanks for your efforts, they're very much appreciated!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Static member initialization with class template
    By threahdead in forum C++ Programming
    Replies: 6
    Last Post: 04-28-2011, 12:16 AM
  2. Replies: 4
    Last Post: 08-29-2010, 04:33 PM
  3. Replies: 4
    Last Post: 12-12-2002, 02:32 PM
  4. Why member initialization?
    By d00b in forum C++ Programming
    Replies: 7
    Last Post: 06-13-2002, 03:05 PM
  5. Data member initialization
    By Fyodorox in forum C++ Programming
    Replies: 4
    Last Post: 04-29-2002, 11:09 PM