Ad

Definition Of Struct Template Value In Constructor / Member Function

- 1 answer

I'm working with a Pascal library that uses UCSD Strings. I created this template struct for making working with them easier:

template <std::size_t N>
struct DString {
    unsigned Reference, Size = N;
    char String[N];
};
#define MAKE_STRING(X) DString<sizeof(X)>{ 0x0FFFFFFFF, sizeof(X) - 1, X}

auto foo = MAKE_STRING("Foo");

I know it does not cover WideChar cases but the library does neither in the first place so I'm safe in that regard.

Anyway, my problem is that I don't want to use a macro and instead would like to create a constructor. So I was wondering if does C++ offers a possibility of implementing something like this pseudocode:

template <std::size_t N>
struct DString {
    unsigned Reference, Size = N;
    char String[N];
    DString<sizeof(s)>(const char* s, unsigned r = 0x0FFFFFFFF): 
        String(s), Reference(r) {}
};

auto foo = DString("Foo");

Of course, it does not need to be a "constructor". It is just an example.

I also tried this:

template <std::size_t N>
struct DString {
    unsigned Reference, Size = N;
    char String[N];

    inline static DString build(const char* X) {
        return DString<sizeof(X)>{ 0x0FFFFFFFF, sizeof(X) - 1, X};
    }
};

auto foo = DString::build("Foo");

But that in itself represents another issue. Because now I cannot reference the static function from DString without doing DString< size >::build(...);.

What can I do in this case?

Ad

Answer

If you can use at least C++17... using a delegate constructor and CTAD...

You can add in DString an additional template constructor (maybe private), otherwise you can't initialize, directly, a char[] with a char const *

template <std::size_t ... Is>
DString (std::index_sequence<Is...>, char const * s, unsigned r)
  : Reference{r}, Size{N}, String{ s[Is]... }
{ }

Next you have to call the new constructor from the old one

DString (char const * s, unsigned r = 0x0FFFFFFFFu): 
  DString(std::make_index_sequence<N>{}, s, r)
  { }

Last, you have to add an explicit deduction guide (given that you want a DString<3> from a char const [4]

template <std::size_t N>
DString (char const (&)[N], unsigned = 0u) -> DString<N-1u>;

and the automatic deduction works.

The following is a full compiling example

#include <utility>
#include <iostream>

template <std::size_t N>
struct DString {
  private:
    template <std::size_t ... Is>
    DString (std::index_sequence<Is...>, char const * s, unsigned r)
      : Reference{r}, Size{N}, String{ s[Is]... }
    { }

  public:
    unsigned Reference, Size = N;
    char String[N];

    DString (char const * s, unsigned r = 0x0FFFFFFFFu): 
      DString(std::make_index_sequence<N>{}, s, r)
      { }
        
};

template <std::size_t N>
DString (char const (&)[N], unsigned = 0u) -> DString<N-1u>;

int main()
{
  auto foo = DString{"Foo"};
}
Ad
source: stackoverflow.com
Ad