std::initializer_list with Multiple Types
Asked Answered
G

3

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)?

Grados answered 13/1, 2014 at 22:24 Comment(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.Nickelous
O
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);
}
Outpour answered 13/1, 2014 at 22:38 Comment(0)
M
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.

Mahound answered 14/12, 2022 at 23:57 Comment(0)
E
-7

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;
}
Eldreda answered 5/2, 2017 at 20:29 Comment(6)
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?Rowlett
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.Eldreda
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.Rowlett
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.Cyclostyle
@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.Aurar
@Kröw I don't know what you mean. I said this example should just use Person(string, int), what is metaphorical about that?Rowlett

© 2022 - 2024 — McMap. All rights reserved.