2

This code is from
https://en.cppreference.com/w/cpp/language/fold

template<typename T, typename... Args>
void push_back_vec(std::vector<T>& v, Args&&... args){
    static_assert((std::is_constructible_v<T, Args&&> && ...));
    (v.push_back(std::forward<Args>(args)), ...);
}

I do not understand why static assert checks for Args&& and not for Args?

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Nick
  • 9,962
  • 4
  • 42
  • 80

1 Answers1

1

This is done for corner cases like this one, when you have only type declaration but no definition (std::is_constructible on incomplete types - in which case is_constructible is UB ):

struct B;

struct A {
    A(const A&) = default;
    A(const B&) {}

    A(A&&) = default;
    A() = default;
};
B&& getB();

template<typename T, typename... Args>
void push_back_vec(std::vector<T>& v, Args&&... args){
    static_assert((std::is_constructible_v<T, Args&&> && ...));
    (v.push_back(std::forward<Args>(args)), ...);
}

template<typename T, typename... Args>
void push_back_vec2(std::vector<T>& v, Args&&... args){
    static_assert((std::is_constructible_v<T, Args> && ...));
    (v.push_back(std::forward<Args>(args)), ...);
}

int main(int argc, char* argv[])
{
    std::vector<A> a;

    push_back_vec(a, A(), A());
    push_back_vec2(a, A(), A());

    A aa;
    push_back_vec(a, aa, aa, A());
    push_back_vec2(a, aa, aa, A());


    push_back_vec(a, getB());
    // code below won't compile
    //push_back_vec2(a, aa, A(), getB());
}

Live example

bartop
  • 9,971
  • 1
  • 23
  • 54
  • *"code below won't compile"* But `push_back_vec(a, getB());` also doesn't compile. Both lines give me `undefined reference to 'getB'`. Am I missing something? – HolyBlackCat Oct 16 '19 at 10:47
  • @HolyBlackCat Compiles fine for me: https://godbolt.org/z/TVM3Ap . Sure, won't link, but that's different story. – bartop Oct 16 '19 at 10:49
  • Huh. Clang does complain about `push_back_vec2(a, aa, A(), getB());`, but GCC doesn't. – HolyBlackCat Oct 16 '19 at 10:55
  • @HolyBlackCat As I said, UB. Clang is more strict in detection of faults here. IMHO this should be fixed in standard if it's that easy, but that's different story. See this: https://stackoverflow.com/questions/55831521/stdis-constructible-on-incomplete-types – bartop Oct 16 '19 at 10:56