0

I am writing a template function where one of the template parameters is a type with a member function that is itself a template function. When I invoke the template member function and explicitly specify the template parameters, it appears that the code does not compile. This is illustrated in the following minimal example:

This version will compile and run just fine:

#include <iostream>

struct ar_t
{
    int data[2];
    ar_t(void) {data[0] = 10; data[1] = 17;}
    template <const std::size_t idx> int get(void) const {return data[idx];}
};

template <const std::size_t val> struct idx_t {};

template <const std::size_t val> int idx_ar1(const ar_t& ar, const idx_t<val>& idx)
{
    return ar.get<val>();
}

int main(int argc, char** argv)
{
    ar_t x;
    const std::size_t index = 1;
    idx_t<index> i;
    idx_ar1(x,i);
    return 0;
}

whereas this version will not:

#include <iostream>

struct ar_t
{
    int data[2];
    ar_t(void) {data[0] = 10; data[1] = 17;}
    template <const std::size_t idx> int get(void) const {return data[idx];}
};

template <const std::size_t val> struct idx_t {};

template <typename arr_type, const std::size_t val> int idx_ar1(const arr_type& ar, const idx_t<val>& idx)
{
    return ar.get<val>();
}

int main(int argc, char** argv)
{
    ar_t x;
    const std::size_t index = 1;
    idx_t<index> i;
    idx_ar1(x,i);
    return 0;
}

Note the difference in the template parameters for idx_ar1. The error message I get with g++ 11.1 and -std=c++20 is:

main.cc: In function ‘int idx_ar1(const arr_type&, const idx_t<val>&)’:
main.cc:14:24: error: expected primary-expression before ‘)’ token
   14 |     return ar.get<val>();
      |                        ^
main.cc: In instantiation of ‘int idx_ar1(const arr_type&, const idx_t<val>&) [with arr_type = ar_t; long unsigned int val = 1]’:
main.cc:22:12:   required from here
main.cc:14:18: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘long unsigned int’ to binary ‘operator<’
   14 |     return ar.get<val>();
      |

How can I get around this? I require preciesly the behaviour used in the second example. This appears to be a bug in parsing the syntax, or I don't quite have a detailed understanding of the way the member function is being declared.

wvn
  • 624
  • 5
  • 12
  • First of all, in `main`, is `idx_t i` now valid C++? There, `index` is not a type, but the name of a variable of type `size_t`.. – Kaz Aug 11 '22 at 00:48
  • 4
    You need `return ar. template get();` in the 2nd version because it's dependent on a template parameter. – cigien Aug 11 '22 at 00:49
  • Do not use `(void)` in C++ other than when preparing C-compatible header files. `(void)` is a hack that was added to ANSI C because `()` meant "function that doesn't declare how many arguments it takes". C++ never had such a thing: but it adopted `(void)` for better C compatibility. It makes no sense on a class member function. – Kaz Aug 11 '22 at 00:51
  • The deduction of the template parameters of a template function in C++ depends on the function arguments. The function is called with certain arguments and those have types. Those actual argument types are matched with the template types in the parameter signature from which the template is deduced. If the function has no arguments, deduction has nothing to go on; you have to explicitly specify it. Hence @cigien's comment. – Kaz Aug 11 '22 at 00:53
  • @Kaz index is a const std::size_t, which is a valid template parameter given the struct declaration. – wvn Aug 11 '22 at 01:06
  • 1
    @wvn Ah, doh, of course; I took another look at it. It's a template parameter of `size_t`; which we are instantiating as 1. – Kaz Aug 11 '22 at 05:19

1 Answers1

1

Try compiling with Clang, too - sometimes it gives better errors than GCC (sometimes worse):

":14:15: error: missing 'template' keyword prior to dependent template name 'get'"

jbapple
  • 3,297
  • 1
  • 24
  • 38
  • Got this error with Clang. Took me a while to figure out that `input.succeed<0>()` should be replace with `input.template succeed<0>()`. Never saw this syntax before. In my case it's needed when I'm calling this method from another templated function, but not from plain source. – foxesque Apr 22 '23 at 13:25