Я играл с выведенными типами возвращаемого значения в определениях, которые разрешают тот же тип, что и объявление. Это работает:
template <typename>
struct Cls {
static std::size_t f();
};
template <typename T>
decltype(sizeof(int)) Cls<T>::f() { return 0; }
Но если я изменю определение на что-то, что должно быть эквивалентно, заменив sizeof(int)
на sizeof(T)
он не работает
template <typename T>
decltype(sizeof(T)) Cls<T>::f() { return 0; }
gcc error (clang почти идентичен):
error: prototype for ‘decltype (sizeof (T)) Cls<T>::f()’ does not match any in class ‘Cls<T>’
decltype(sizeof(T)) Cls<T>::f() { return 0; }
^~~~~~
so.cpp:4:24: error: candidate is: static std::size_t Cls<T>::f()
static std::size_t f();
^
Та же проблема возникает при использовании типов параметров функции:
template <typename>
struct Cls {
static void f(std::size_t);
};
template <typename T>
void Cls<T>::f(decltype(sizeof(T))) { } // sizeof(int) works instead
Еще страннее, если соответствие декларации и определения и оба используют decltype(sizeof(T))
, он успешно компилируется, и я могу static_assert
, что тип возврата size_t
. Следующие компиляции успешно выполняются:
#include <type_traits>
template <typename T>
struct Cls {
static decltype(sizeof(T)) f();
};
template <typename T>
decltype(sizeof(T)) Cls<T>::f() { return 0; }
static_assert(std::is_same<std::size_t, decltype(Cls<int>::f())>{}, "");
Обновление с помощью другого примера. Это не зависимый тип, но все еще не выполняется.
template <int I>
struct Cls {
static int f();
};
template <int I>
decltype(I) Cls<I>::f() { return I; }
Если я использую decltype(I)
как в определении, так и в декларации, он работает, если я использую int
как в определении, так и в декларации, но он имеет два отличия.
Обновление 2:
Аналогичный пример. Если Cls
изменен, чтобы не быть шаблоном класса, он успешно компилируется.
template <typename>
struct Cls {
static int f();
using Integer = decltype(Cls::f());
};
template <typename T>
typename Cls<T>::Integer Cls<T>::f() { return I; }
Обновление 3: Другой неудачный пример от М.М. Шаблонная функция-член неимметрированного класса.
struct S {
template <int N>
int f();
};
template <int N>
decltype(N) S::f() {}
Почему это незаконно, если декларация и определение не согласуются только с зависимым типом? Почему это затрагивается, даже если сам тип не зависит от template <int I>
выше?