I've been playing with deduced return types in definitions that resolve to the same type as the declaration. This works:
template <typename>
struct Cls {
static std::size_t f();
};
template <typename T>
decltype(sizeof(int)) Cls<T>::f() { return 0; }
But if I change the definition to something that should be equivalent by replacing sizeof(int) with sizeof(T) it fails
template <typename T>
decltype(sizeof(T)) Cls<T>::f() { return 0; }
gcc's error (clang is almost identical):
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();
^
The same problem arises with function parameter types:
template <typename>
struct Cls {
static void f(std::size_t);
};
template <typename T>
void Cls<T>::f(decltype(sizeof(T))) { } // sizeof(int) works instead
Stranger yet, if the declaration and definition match and both use decltype(sizeof(T)) it compiles successfully, and I can static_assert that the return type is size_t. The following compiles successfully:
#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())>{}, "");
Update with another example. This isn't a dependent type but still fails.
template <int I>
struct Cls {
static int f();
};
template <int I>
decltype(I) Cls<I>::f() { return I; }
If I use decltype(I) in both the definition and declaration it works, if I use int in both the definition and declaration it works, but having the two differ fails.
Update 2:
A similar example. If Cls is changed to not be a class template, it compiles successfully.
template <typename>
struct Cls {
static int f();
using Integer = decltype(Cls::f());
};
template <typename T>
typename Cls<T>::Integer Cls<T>::f() { return I; }
Update 3: Another failing example from M.M. A templated member function of a non-templated class.
struct S {
template <int N>
int f();
};
template <int N>
decltype(N) S::f() {}
Why is it illegal for the declaration and definition to disagree with a dependent type only? Why is it affected even when the type itself isn't dependent as with the template <int I> above?