Search code examples
c++templatesc++17metaprogramming

How can I move or assign one vector into another depending of their type using if constexpr?


I wanted to move or assign a std::vector<Scalar> into a std::vector<float> depending on the type Scalar.

If Scalar is float then move, else copy.

I tried this code

#include <vector>

using Scalar = double;

int main()
{
    std::vector<Scalar> x(10);
    std::vector<float> y(10);

    if constexpr(std::is_same<Scalar, float>::value)
        y = std::move(x); // line 11 (does not compile)
    else
        y.assign(x.begin(), x.end());

    return 0;
}

but I get

main.cpp:11:24: error: no match for ‘operator=’ (operand types are ‘std::vector<float>’ and ‘std::remove_reference<std::vector<double>&>::type’ {aka ‘std::vector<double>’})
   11 |         y = std::move(x);
      |                        ^

I thought that since std::is_same<Scalar, float>::value is evaluated to false at compile-time, then the line below would not be compiled.

I compiled it using g++ -std=c++17 main.cpp -o exec.

How can I move/assign x into y depending on the Scalar type?


Solution

  • As pointed out by HolyBlackCat in a comment, and as stated in cppref: "Outside a template, a discarded statement is fully checked." (https://en.cppreference.com/w/cpp/language/if).

    Here is one potential solution involving one new template function

    #include <vector>
    
    template <typename U, typename V>
    void move_or_copy(std::vector<U>& y, std::vector<V>&& x) {
        if constexpr(std::is_same<U,V>::value) {
            y = std::move(x);
        } else {
            y.assign(x.begin(), y.end());
        }
    }
    
    
    using Scalar = double;
    
    int main()
    {
        std::vector<Scalar> x(10);
        std::vector<float> y(10);
    
        move_or_copy(y, x);
    
        return 0;
    }