0

I'm trying to use std::initializer_list in a constructor to accept variable number of arguments. With non-template class it works fine, but with template class it gives compiling errors. Could anyone possiblly point me to the right direction? My g++ is capable of C++17.

#include <iostream>
#include <vector>
#include <type_traits>
#include <initializer_list>

struct Nontemplate
{
    // std::initializer_list for a function taking variable number of arguments
    template <class Iterator>
    Nontemplate(std::initializer_list<Iterator> list) {
        std::cout << "size: " << list.size() << std::endl;
        for(auto it : list) {
            std::cout << *it << std::endl;
        }
    }
};

template <class T, class TIterator>
struct Template
{
    std::vector<T> vec;

    Template(std::initializer_list<TIterator> list)
    {
        if(!std::is_same<typename std::iterator_traits<TIterator>::value_type, T>::value)
            throw std::runtime_error("Iterator value type is not the expected.");

        std::cout << "size: " << list.size() << std::endl;

        vec.clear();
        vec.reserve(list.size());
        for(T val : list)
            vec.push_back(val);
    }
};

int main()
{
    double vec[] = {0,1,2,3,4,5};

    Nontemplate cls0({vec, vec+2, vec+3, vec+4}); // no problem
    //Template cls1({vec, vec+2, vec+3, vec+4});  // compiling error
    return 0;
}

Thanks in advance.

12
  • What are the compilation errors you're getting? Commented Dec 13, 2020 at 3:19
  • @1201ProgramAlarm: The error message is: main.cpp:42:45: error: class template argument deduction failed: 42 | Template cls1({vec, vec+2, vec+3, vec+4}); // compiling error Commented Dec 13, 2020 at 3:38
  • 1
    You need to pass Template Argumnets in Template<?,?> cls1.... Commented Dec 13, 2020 at 4:14
  • 1
    Elements of list are of type TIterator, not T. TIterator may or may not be the same as T* Commented Dec 13, 2020 at 4:23
  • 1
    @jianz Template<double, double*> should fix your compiler error, but there's no template argument deduction here. You could just have one template parameter: TIterator and base your vector on that: std::vector<typename std::iterator_traits<TIterator>::value_type> vec; Then you don't have to supply the types yourself to the template. Plus it becomes a compile time check. Commented Dec 13, 2020 at 5:58

1 Answer 1

1

Template cls1({vec, vec+2, vec+3, vec+4}) has no ways to deduce T.

You might use

Template<double, double*> cls1({vec, vec+2, vec+3, vec+4});

or provide custom deduction guide:

template <typename It>
Template(std::initializer_list<It>)
-> Template<typename std::iterator_traits<It>::value_type, It>;

Or simplify your class to remove that T

template <class TIterator>
struct Template
{
    using T = typename std::iterator_traits<TIterator>::value_type;
    std::vector<T> vec;

    Template(std::initializer_list<TIterator> list)
    {
        std::cout << "size: " << list.size() << std::endl;

        vec.clear();
        vec.reserve(list.size());
        for(T val : list)
            vec.push_back(val);
    }
};
Sign up to request clarification or add additional context in comments.

2 Comments

This is wonderful. Before your post, I have been using the "Template<double, double*>" method. What I was looking for are the other two alternatives you provided here. Thanks a lot. Could you possible correct typos - I have already accepted this as the solution. 1) custom deduction guide method: "-> Template<typename std::iterator_traits<It>::value_type, It>;" 2) Removing T method: "using T = typename std::iterator_traits<TIterator>::value_type;"
@jianz: typos fixed. (feel free to edit if it remains some).

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.