0

I'm trying to implement a templated function that takes as argument either a std::vector<float>& or a std::vector<std::vector<float>>. Below a simplified version of my code.

I'm getting errors like:

C2440 'initializing' cannot convert from initializer list

when I tried to implement this when calling function PlotDataset().

What is the best/cleanest way to achieve this?

template<typename T>
plot(T& y)
{
    // depending on whether T is a float or a std::vector<float>,
    // I want to set my for loop differently
    if(std::is_same<T, std::vector<std::vector<float>>>::value)
    {
        for(size_t n{0}; n < y.size(); n++)
        {
            // axes is a shared_ptr, while PlotDataset is a class constructor
            // taking a std::vector<float> as argument
            axes->addDataset(PlotDataset(y.at(n)));
        }
    }
    else if(std::is_same<T, std::vector<float>>::value)
    {
            axes->addDataset(PlotDataset(y))
    }
}
rturrado
  • 7,699
  • 6
  • 42
  • 62
Fab D'
  • 5
  • 2
  • 5
    IMO a template is overkill here. A function that's overloaded for `std::vector` and `std::vector>` seems to be better suited. – Lukas-T Jun 22 '21 at 16:57
  • 2
    Also, if you did go this route, you would need to use `if constexpr (...)` instead of `if (...)` – Remy Lebeau Jun 22 '21 at 16:58
  • Can you show the calls to `plot`? – rturrado Jun 22 '21 at 17:06
  • Thanks! Yes I agree it could be an overkill. I thought it was cleaner and leaner to avoid code repetition due to a silly ".at()" difference between the two overloaded methods. – Fab D' Jun 23 '21 at 11:37

1 Answers1

3

Here you will have to use if constexpr

if constexpr (std::is_same<T, std::vector<std::vector<float>>>::value)
{
    ...
}
else if constexpr (std::is_same<T, std::vector<float>>::value)
{
       ...
}

But now you have a function template that works only for 2 very specific types and doesn't do anything for any other type. I think in this case it would be much better (easier to use, clearer interface, less overhead from if constexpr) to use an overloaded function:

plot(std::vector<std::vector<float>> &y) 
{
    for(size_t n{0}; n < y.size(); n++)
    {
        axes->addDataset(PlotDataset(y.at(n)));
    }
}

plot(std::vector<float> &y)
{
    axes->addDataset(PlotDataset(y))
}

If you want to support datatypes other than float you could still make these templates.

Lukas-T
  • 11,133
  • 3
  • 20
  • 30
  • Here's a Compiler Explorer example of the `if constexpr` (you shouldn't go for this) option: https://godbolt.org/z/EKrYjn48o – rturrado Jun 22 '21 at 17:38
  • I had never seen `constexpr` used with `if` statements and I can't figure out the difference and why it works this way, while the compiler has troubles deducing the type of T otherwise. What's the logic here? – Fab D' Jun 23 '21 at 11:40
  • @FabD' `if constexpr` is special. In very rough terms you can think of it as "compile time if". When an actual function is created from this template (when it's instantiated) the `if constexpr` is evulated and only if it's true the block after it will be compiled. But I suggest to take a look at the [reference](https://en.cppreference.com/w/cpp/language/if) or [this question](https://stackoverflow.com/questions/43434491/difference-between-if-constexpr-vs-if) for a more detailed answer. – Lukas-T Jun 23 '21 at 11:51