10

I'm having trouble with std::initializer_list. I reduced it down to a simple example:

#include <initializer_list>
#include <cstdio>


class Test {
    public:
        template <typename type> Test(const std::initializer_list<type>& args) {}
};

int main(int argc, char* argv[]) {
    Test({1,2});

    getchar();
    return 0;
}

When compiled using g++ test_initializer.cpp -std=c++0x, it compiles and runs well. However, if line 11 is changed to Test({1,2.0});, one gets:

ian@<host>:~/Desktop$ g++ test_initializer.cpp -std=c++0x
test_initializer.cpp: In function ‘int main(int, char**)’:
test_initializer.cpp:11:14: error: no matching function for call to ‘Test::Test(<brace-enclosed initializer list>)’
test_initializer.cpp:11:14: note: candidates are:
test_initializer.cpp:7:28: note: template<class type> Test::Test(const std::initializer_list<_Tp>&)
test_initializer.cpp:5:7: note: constexpr Test::Test(const Test&)
test_initializer.cpp:5:7: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const Test&’
test_initializer.cpp:5:7: note: constexpr Test::Test(Test&&)
test_initializer.cpp:5:7: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘Test&&’

I suspect this happens because the compiler can't figure out what type to make the initializer list. Is there a way to fix the example so that it works with different types (and still uses initializer lists)?

1
  • 1
    If you need multiple types, provide a constructor that's a variadic template: template <typename... T> Test(T... args);. I don't believe you can use an initializer list for this. Commented Jan 13, 2014 at 22:31

3 Answers 3

12

An std::initializer_list takes only one type. If you need different types, you can use variadic templates:

template<typename... Args>
Test(Args&&... args);

/* ... */

int main()
{
    Test(1, 2.0);
}
Sign up to request clarification or add additional context in comments.

Comments

1

Would a std::tuple<int.double> work for the OP? If the code will always have a int followed by a double, then the OP could get strict type-checking for all arguments, which the variable arguments solution does not allow. The std::tuple<>, however, would not work for any number or order of values, so may not be appropriate for all use cases.

1 Comment

Note that this only work if the types are known in advance, the types cannot be deduced: stackoverflow.com/q/50031190/5267751
-6

Let the initializer_list hold the most arbitrary pointers, void*, and do your own casting from there. Here is an example.

#include <initializer_list>
#include <iostream>

using std::initializer_list;
using std::cout;
using std::endl;

class Person {
    private:
        string _name;
        int _age;
    public:
        Person(initializer_list<void*> init_list) {
            auto it = init_list.begin();
            _name = *((string*)(*it));
            it++;
            _age = *((int*)(*it));
        }
        void print() {
            cout << "name: " << _name << ". age: " << _age << endl;
        }
};

int main(void) {
    string name{"Vanderbutenburg};
    int age{23};
    Person p{&name,&age};
    p.print(); // "name: Vanderbutenburg. age: 23"

    return 0;
}

6 Comments

For this to work you have to know in advance the number of arguments and their types, to be able to cast them back. If you know that why not just write Person(string, int) instead?
Your suggestion would certainly be nicer to the eyes, but I was just commenting on a way to circumvent the issue posed by the author. Afterall, this is what the author asked. "Is there a way to fix the example so that it works with different types (and still uses initializer lists)?" The main point is that it is possible. Would I ever do it that way? Of course not.
The OP's issue is that std::initializer_list is not the right tool for the job. Smacking the problem with a large hammer until it compiles doesn't change that.
When someone asks a question, sometimes it's better to tell them what they need to know, not what they want to know. What people need to know is that code like this is terrible and defeats the point of a language that goes to lengths to be type-safe and expressive.
@JonathanWakely Please be more concrete. You can say the problem with the question without resorting to arbitrary metaphors that may not apply and server to confuse. It makes it hard to understand what you're trying to say otherwise.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.