Alex Koksin
Alex Koksin

Reputation: 129

How to specify template function for STL container?

I need to write values of different types to a std::wstringstream. At one time we need to write one ore more values. I have tried to implement it like this:

wstringstream _str;     

template<typename ValueType> //(1)
void WriteValue(const ValueType& val)
{
    _str << val;
}

template<typename ValueType> //(2)
void WriteValue(const std::vector<ValueType>& vals)
{
    for (auto it = vals.begin(); it!= vals.end(); ++it)
    {
        WriteValue<ValueType>(*it);
        _str << L" ";            
    }
}

template<typename ValueType>
void WriteRecord(const std::wstring& name, const ValueType & val)
{
     _str << name;
     WriteValue<ValueType>(val);
}

void Foo()
{
    int bar = 0;
    WriteRecord<int>(L"Lorem", bar); //it's okay

    std::vector<int> buz(4, 0);
    WriteRecord<int>(L"ipsum", buz); //it's error
}

I got the following error :

"cannot convert argument 2 from 'std::vector< int, std::allocator < int > >' 
to 'int &'". As seen compiler tries to pass a vector to (1), not (2).

Why so? Is it possible to make it choose (2) specialized function template?

Upvotes: 1

Views: 58

Answers (2)

Praetorian
Praetorian

Reputation: 109089

std::vector<int> buz(4, 0);
WriteRecord<int>(L"ipsum", buz);
//          ^^^

You're telling the compiler ValueType is int but then you're passing vector<int> as the argument. The compiler is perfectly capable of deducing template argument types, so stop specifying them everywhere unnecessarily. Your Foo function should look like this:

void Foo()
{
    int bar = 0;
    WriteRecord(L"Lorem", bar);

    std::vector<int> buz(4, 0);
    WriteRecord(L"ipsum", buz);
}

Similarly, remove the explicitly specified template arguments in the calls to WriteValue in the other functions.

Upvotes: 1

Rakete1111
Rakete1111

Reputation: 48928

WriteRecord<int>(L"ipsum", buz);
           ^^^^^

Here you explicitly say that ValueType should be an int. So the function signature is:

void WriteRecord(const std::wstring& name, const int& val)

And when you try to pass a std::vector as second argument, the compiler can't convert the std::vector to an int.

For functions, there is rarely a need to explicitly name the type of the template argument, you writing the call like this will work:

WriteRecord(L"ipsum", buz); //Compiler deduces ValueType

If you really need to specify the template argument, use decltype:

WriteRecord<decltype(buz)>(L"ipsum", buz);

or just write it out (not recommended)

WriteRecord<std::vector<int>>(L"ipsum", buz);

Upvotes: 2

Related Questions