0

So I've got a templatized class which has a templatized static constexpr bool. The setup boils down to this:

#include <type_traits>

template <typename T>
class A {
public:
  template <typename U>
  static constexpr bool same = std::is_same_v<T, U>;
};

template <typename T>
bool test() {
  return A<T>::same<int>; // errors
}

int main() {
  A<int>::same<int>;      // compiles perfectly
  test<int>();            // errors
}

When I access it with actual types like A<int>::same<int>, it compiles just fine, but when I try to access it with a template type, as in the test() function above, it errors. Here is the full list of errors:

constexpr_value.cpp: In function ‘bool test()’:
constexpr_value.cpp:12:21: error: expected primary-expression before ‘int’
   12 |   return A<T>::same<int>;
      |                     ^~~
constexpr_value.cpp:12:21: error: expected ‘;’ before ‘int’
   12 |   return A<T>::same<int>;
      |                     ^~~
      |                     ;
constexpr_value.cpp:12:24: error: expected unqualified-id before ‘>’ token
   12 |   return A<T>::same<int>;
      |                        ^
constexpr_value.cpp: In instantiation of ‘bool test() [with T = int]’:
constexpr_value.cpp:16:12:   required from here
constexpr_value.cpp:12:16: error: ‘A<int>::same<U>’ missing template arguments
   12 |   return A<T>::same<int>;
      |                ^~~~

The first three errors are from the template itself, and they show up even when I don't use the test() function at all, so it seems like the compiler is assuming A<T>::same<int> is an invalid statement before even checking any specific Ts.

I don't understand these errors at all. Why does A<int>::same<int> compile perfectly, but as soon as you use template types, it doesn't like it at all? I don't even know where to begin fixing this, because the errors tell me nothing. The only difference between compiling and not is using <T> instead of <int>, so is there something I can do with T to tell the compiler that this is a valid statement?

1 Answers1

3

The template code is not equivalent to A<int>::same<int>. This will also compile:

template <typename T>
bool test() {
  return A<int>::same<int>;
}

Returning to the erroneous code. The latest GCC 12.1 would produce the hint in the warning:

constexpr_value.cpp: In function 'bool test()':
constexpr_value.cpp:12:16: warning: expected 'template' keyword before dependent template name [-Wmissing-template-keyword]
   12 |   return A<T>::same<int>; // errors
      |                ^~~~

As the warning message suggests the fix:

template <typename T>
bool test() {
  return A<T>::template same<int>;
}
//             ^^^^^^^^

See the hot question Where and why do I have to put the "template" and "typename" keywords? for more info.

273K
  • 29,503
  • 10
  • 41
  • 64
  • Ah, I see. I felt like there was some sort of keyword/specifier I was missing, but I didn't know what it was. I've never actually seen the `template` keyword used like that. Also, the error message isn't saying "missing template **keyword**" or "missing template **specifier**", it says "arguments", and as far as I understand it, that should mean the arguments passed in to the template, no? – Arthur Bouvier Aug 21 '22 at 23:35
  • You seemed to miss the warning just before the error: `warning: expected 'template' keyword before dependent template name [-Wmissing-template-keyword]` `return A::same; // errors`. It is very important to read compiler messages from beginning, not filtering them with important/unimportant, all are important. – 273K Aug 21 '22 at 23:38
  • I was just compiling with `g++ constexpr_value.cpp`, I didn't pass any specific flags to it. I definitely should've enabled warnings to figure out the issue though, I just didn't think to do so, since I've mostly been working on small, fairly simple projects recently that just didn't need warnings. I will definitely do that next time. Thanks! – Arthur Bouvier Aug 21 '22 at 23:45
  • None of flags is required: https://godbolt.org/z/vbbYhqYMq - the GCC warning appears in the beginning of the output. You are right, I see the older GCC 11.3 does not raise the warning https://godbolt.org/z/4xxsd9ec3 – 273K Aug 21 '22 at 23:47
  • Ah, yeah, I'm using GCC 11.1.0, which was the default version on my system. – Arthur Bouvier Aug 21 '22 at 23:52