Аргумент шаблона по умолчанию не может быть указан в определении члена шаблона класса вне класса

template<typename Tp, class C = std::vector<Tp>>
struct A {
    C s{};    
    void change(const C&);
};

template<typename Tp, class C = std::vector<Tp>> //Ошибка (активный) E0953
void A<Tp, C>::change(const C& seq) {/*...*/ }

Очевидно, что при определении члена класса, нет смысла указывать аргумент шаблона по умолчанию. Но вопрос в том, почему компилятор это считает ошибкой? (Может плохо смотрел, но кажется не было похожего вопроса).


Ответы (1 шт):

Автор решения: dIm0n

http://eel.is/c++draft/temp.param#12

A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class.

Релевантный баг в gcc

Почему так сделано?

Например, в следующем примере

template <class T = int>
struct A {
    T foo();
};

int main() {
    auto a = A{};
}

мы можем использовать дефолтный аргумент и не определять/инстанцировать функцию foo, потому что она не используется. А если бы можно было указывать дефолтные аргументы вне класса

template <class T>
struct A {
    T foo();
};

template <class T = int>
T A<T>::foo() {
    return T{};
}

int main() {
    auto a = A{};
}

то, для того чтобы узнать дефолтный аргумент, необходимо было бы искать определение функции, которая нам не нужна.

Теоретически можно сохранить возможность повторного определения точно такого же аргумента, как у вас в примере

template <class T = int>
struct A {
    T foo();
};

template <class T = int>
T A<T>::foo() {
    return T{};
}

int main() {
    auto a = A{};
}

но это не имеет смысла, потому что нет плюсов (по крайней мере я не вижу, для чего это может использоваться), но есть минус – дополнительная нагрузка на компиляторы для проверки равенства аргументов.

→ Ссылка