Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use std::array.size() as a template parameter when a class has a non-constexpr std::array

The following is a toy example

The class student has a std::array<char, 15> called name and an integer age. A student has a member function called encode that calls a global template function encode using name.size() as a template parameter.

The code is shown below:

//main.cpp
#include <iostream>
#include <array>

template <unsigned long num1>
unsigned long encode(unsigned long num2){
    return num1 + num2;
}


struct student {
    std::array<char, 15> name;
    int age;
    student(const std::array<char, 15>& name, int age):
        name(name),
        age(age)
    {}
    unsigned long encode(){
        return ::encode<name.size()>(age);
    }
};

int main(){
    std::array<char, 15> name = {"Tim"};
    student Tim(name, 17);
    std::cout << Tim.encode();
}

However, this produces the following compiler error

>g++ main.cpp -std=c++11

main.cpp: In member function 'long unsigned int student::encode()':
main.cpp:22:43: error: use of 'this' in a constant expression
   22 |                 return ::encode<name.size()>(age);
      |                                           ^
main.cpp:22:45: error: no matching function for call to 'encode<((student*)this)->student::name.std::array<char, 15>::size()>(int&)'
   22 |                 return ::encode<name.size()>(age);
      |                        ~~~~~~~~~~~~~~~~~~~~~^~~~~
main.cpp:9:15: note: candidate: 'template<long unsigned int num1> long unsigned int encode(long unsigned int)'
    9 | unsigned long encode(unsigned long num2){
      |               ^~~~~~
main.cpp:9:15: note:   template argument deduction/substitution failed:
main.cpp:22:45: error: use of 'this' in a constant expression
   22 |                 return ::encode<name.size()>(age);
      |                        ~~~~~~~~~~~~~~~~~~~~~^~~~~
main.cpp:22:42: note: in template argument for type 'long unsigned int'
   22 |                 return ::encode<name.size()>(age);

Is it required I do ::encode<15>(age) to solve this problem, because I thought one of the major benefits of a std::array is being able to carry a size rather than having to store the size in some extra variable (or hardcoding the size).

g++ version: 14.1.0

like image 988
timmy george Avatar asked Jan 21 '26 22:01

timmy george


1 Answers

I dislike including the <tuple> header just to use std::tuple_size_v.

I think you can also express the same using

return ::encode<decltype(name){}.size()>(age);
  • decltype(name) gives you the type, without the need of the this pointer
  • {} creates an instance
  • .size() gives you the size of that instance

Since this is constexpr, this evaluates to 15 at compile time and there's no actual overhead for the creation of the temporary instance.

like image 97
Thomas Weller Avatar answered Jan 23 '26 15:01

Thomas Weller