c++c++11templatesstdarray

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 though 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


Solution

  • 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);
    

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