Search code examples
c++templates

Template to return vector of elements


I'm trying to write a template that returns a vector of elements of specific type. Unfortunately I'm encountering warnings and errors that I am finding hard to resolve. I suspect I might need to use std::enable_if rather than std::is_same_v, but not sure of the correct way to go about it.

Below is a simplified example that reproduces the issue.

I would appreciate if someone could explain why I get the warnings and errors and how to best resolve them.

Thanks!

#include <string>
#include <vector>
#include <iostream>

struct Person
{
    std::string name;
    double age;
    char gender;

    template<class T>
    std::vector<T> GetValue()
    {
        std::vector<T> v;

        if (std::is_same_v<T, double>)
            v.push_back(age);
        if (std::is_same_v<T, char>)
            v.push_back(gender);
        if (std::is_same_v<T, std::string>)
            v.push_back(name);

        return v;
    }   
};

int main()
{
    Person p{ "Joe", 33, 'm' };
    
    std::vector<double> v1 = p.GetValue<double>();
    std::cout << "double: " << v1[0] << std::endl;

    // Warning with next line
    std::vector<char> v2 = p.GetValue<char>();
    std::cout << "char: " << v2[0] << std::endl;

    // Error with next line
    std::vector<std::string> v3 = p.GetValue<std::string>();
    std::cout << "string: " << v3[0] << std::endl;

    return 0;
}

Solution

  • The problem is in your GetValue() implementation:

    The push_back statements are compiled for all the ifs, even if the value you attempt to add does not match the type T of the vector.

    Instead you can use if constexpr (requires C++17 on higher), so that the compiler will not compile the branches that do not satisfy the condition:

    std::vector<T> GetValue()
    {
        std::vector<T> v;
    
        if constexpr (std::is_same_v<T, double>)
            v.push_back(age);
        if constexpr (std::is_same_v<T, char>)
            v.push_back(gender);
        if constexpr (std::is_same_v<T, std::string>)
            v.push_back(name);
    
        return v;
    }
    

    A side note:
    Your posted code is missing #include <iostream> in order to compile.