c++templatesctad

Non-type class template argument deduction


I declared a template class which takes a size_t template argument. Here is the class (or struct in this case):

typedef unsigned char byte;

template <size_t NumBytes>
struct Field
{
    bool is_set = false;
    std::array<byte, NumBytes> data;

    Field() = default;
    Field(byte &&val, bool is_set = false);
    Field(std::initializer_list<byte> predef);
};

The idea is to use it for file header fields (ELF in this case). I want to be able to define a field in the following way:

const Field EI_MAG = {0x7F, 0x45, 0x4c, 0x46};

And have it automatically deduce the template argument NumBytes, such that, in this case, EI_MAG would be of type const Field<4>. The compiler complains a lot (of course) and I eventually get to the point of defining a template deduction guide. My best (and latest) attempt is the following:

template <class Type, class... Data>
Field(Type, Data...) -> Field<sizeof...(Data)>;

But the compiler still complains with the following error:

error: invalid use of template-name ‘Field’ without an argument list
   53 |     const Field EI_MAG          = {0x7F, 0x45, 0x4c, 0x46};
      |           ^~~~~

So how should I do it? Is it even possible? If not, how does std::array do it? I've been banging my head for several hours, and I still struggle a bit with how template deduction and template deduction guides work. Any help would be much appreciated.

NOTE: All the code presented is located in a .hpp file , and all struct function definitions are located in the corresponding .cpp file, which is not presented here.


Solution

  • This compiles after the deduction guide is fixed.

    #include <array>
    #include <cstddef>
    
    typedef unsigned char byte;
    
    template <size_t NumBytes>
    struct Field {
      bool is_set = false;
      std::array<byte, NumBytes> data;
    
      Field() = default;
      Field(byte &&val, bool is_set = false);
      Field(std::initializer_list<byte> predef);
    };
    
    template <class... Data>
    Field(Data...) -> Field<sizeof...(Data)>;
    
    const Field EI_MAG = {0x7F, 0x45, 0x4c, 0x46};
    

    It doesn't need class Type.