0

Got a parametrized constructor which accepts size_t variables, and therefore should be called when trying to create an object passing a size_t variable. Instead, compiler tries to call the initializer_list<value_type> constructor, tries to convert the size_t to double, fails and throws an error:

error: non-constant-expression cannot be narrowed from type 'size_t' (aka 'unsigned long') to 'double' in initializer list [-Wc++11-narrowing] Vector whyMe{u};

It does differentiate between String and initializer_list when choosing a constructor, any random integer will still be converted to list of doubles tho, which is also strange as tagging a constructor with explicit (explicit Vector (std::initializer_list<value_type> list)), at least as I understand it, should only allow instances of initializer_list<...> in. Would be grateful for a fix, that doesn't use explicit though, as it may be detrimental to further development.

#include <iostream>

class Vector {
public:
    using value_type = double;
private:
    size_t sz;
    size_t max_sz;
    value_type* values;
public:
    // Constructors
    // parametrized
    Vector (std::initializer_list<value_type> list)
        : sz{list.size()}, max_sz{list.size()}, values{new value_type[list.size()]} {
        
        int tempIterator = 0;
        for (value_type el : list) {
            values[tempIterator] = el;
            ++tempIterator;
        }

        std::cout << "std::initializer_list<value_type> list constructor called" << std::endl;
    }
    Vector(size_t n)
        : sz{0}, max_sz{n}, values{new value_type[n]} {
        
        std::cout << "size_t n constructor called" << std::endl;
    }

    Vector (std::string n): sz{0}, max_sz{0}, values{new value_type[0]} {
        std::cout << "string constructor called " << n << std::endl;
    }

    // Destructors
    ~Vector() {
        delete[] values;
    }
};


int main () {
    std::initializer_list<double> love{1,2,3,4,5,6};
    size_t u{5};
    std::string compiler{"idontwanttolive"};

    Vector wannaDie{love};
    Vector whyMe{u};
    Vector lifeIsNotWorthLiving{compiler};
    return 0;
}

Will also be grateful for any hints to improve my code formatting, use of best practices, etc. cause I am new to the C++ and programming in general.

4
  • @ypnos: Can you explain why the initializer list constructor is preferred in that case and the value of size_t is converted to a initializer list with a single value? Commented Oct 18, 2024 at 9:45
  • 1
    This problem is also present in std::vector. Basically std::initializer_list has higher priority then single value constructor when brace initialization is used. In case of parenthesis initialization, std::initializer_list has to be provided in more explicit manner. godbolt.org/z/qjKq6G6qz cppinsights.io/s/f404fd5d Commented Oct 18, 2024 at 11:31
  • You could have removed at least 90% of this code and still shown the problem. Commented Oct 18, 2024 at 12:18
  • "Will also be grateful for any hints to improve my code formatting, use of best practices, etc. cause I am new to the C++ and programming in general." -- This sort of open-ended, opinion-based feedback is off-topic for Stack Overflow. You should remove this request from your question. (There is a code review site for such feedback.) Commented Oct 18, 2024 at 14:00

1 Answer 1

7

You need to call Vector whyMe(u); if you want to use a regular constructor and not the initializer-list one. Initializing an object with {} through regular constructors will only come into effect if your class does not provide an initializer-list constructor.

Take this example with the standard library's vector:

std::vector<int> v1(10);    // vector of 10 elements with the default value 0
std::vector<int> v2{10};    // vector of 1 element with the value 10

The reason for the different behavior is that std::vector provides a constructor with initializer list and a constructor that takes size_t.

For more explanation with examples, see https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-list

Sign up to request clarification or add additional context in comments.

2 Comments

Just to clarify, as my task is to write the Vector class, it is considered normal behaviour to have to declare a vector with an "n" amount of elements with these brackets "()" instead of these"{}"? Thank you, friend!
@DimaLisovenko • As Bjarne Stroustrup and/or Herb Sutter mentioned in the link "For containers, there is a tradition for using {...} for a list of elements and (...) for sizes:"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.