C++17 template класс со значением аргумента по умолчанию
Сразу прошу прощения, я не знаю что написать в заголовок, ниже я дал минимальный пример кода. Я использую компилятор MSVC C++17. Объясните, почему для некоторых сущностей нужно писать <> при инициализации шаблона, а для некоторых можно опустить (в случае, если для всех аргументов есть значение по умолчанию)? Например, я могу вызвать шаблонную функцию, или создать экземпляр шаблонного класса внутри функции без <>, но если я хочу объявить член класса, то я обязан использовать A<> a вместо A a.
#include <iostream>
template<size_t i = 1>
class A {
public:
size_t foo() {
return i;
}
};
template<size_t i = 1>
size_t foo() {
return i;
}
class B {
public:
A a; // error
A<> a; // okey
static size_t foo1() {
return foo(); // okey
}
template<size_t i = 2>
static size_t foo2() {
return foo(); // okey
}
};
int main() {
A a; // okey
auto &f1 = foo; // error
auto &f1 = foo<>; // okey
auto &f2 = B::foo1; // okey
auto &f3 = B::foo2; // error
auto &f3 = B::foo2<>; // okey
return B().a.foo() + A().foo(); // okey
}
P.S. на godbolt другие компиляторы имели то же поведение, т.е., возможно, это какой-то стандарт, но я не знаю как загуглить.
Ответы (1 шт):
Возможность не писать пустые <> для класса - это частный случай более крупной фичи - возможности выводить шаблонные параметры из аргументов конструктора (CTAD = class template argument deduction).
Поэтому разрешено это плюс-минус только там, где есть какой-то вызов конструктора (есть из чего выводить параметры).
Например так нельзя: std::vector foo();. А так можно: std::vector v = {1,2,3};.
Тогда почему в нестатическом члене класа нельзя? Потому что это бы странно работало. Инициализатор, который там подписан, можно переопределить в списке инициализации в конструкторе. К примеру, вот это заслуженно не компилируется:
struct A
{
std::vector a = {1,2,3}; // Допустим T = int.
A()
: a{1.0, 2.0, 3.0} // Из-за этого {1,2,3} полностью игнорируется.
// Что дальше? Оставляем T = int? Не менять же на double задним числом?
{}
};