Шаблон соответствия с параметром заполнителя для вычета шаблона класса - PullRequest
3 голосов
/ 13 июля 2020

Попытка использовать строковые литералы в качестве параметров шаблона без типа в G CC 10.1. Имейте следующий код:

#include <cstddef>
#include <algorithm>
#include <iostream>

template<std::size_t n> struct fixed_string {
  constexpr fixed_string(char const (&s)[n]) {
    std::copy_n(s, n, this->el);
  }
  constexpr fixed_string(fixed_string<n> const& s) {
    std::copy_n(s.el, n, this->el);
  }
  constexpr bool operator==(fixed_string const&) const = default;
  constexpr auto operator<=>(fixed_string const&) const = default;
  char el[n];
};
template<std::size_t n> fixed_string(char const(&)[n])->fixed_string<n>;

template<fixed_string str>
class Base {
public:
  Base() {
    std::cout << str.el << std::endl;
  }
};

template<fixed_string str>
class Derived : public Base<str> {
};


int main(void) {
  Derived<"Hello World"> x;
}

Base сам по себе отлично работает, пытаясь выяснить, как передать строковые литералы вверх по иерархии классов. Я думал, что конструктор копирования сработает, и G CC выплевывает это прекрасное сообщение об ошибке и смеется над моей попыткой:

error: no matching function for call to ‘fixed_string(fixed_string<...auto...>)’
note: candidate: ‘template<long unsigned int n> fixed_string(const fixed_string<n>&)-> fixed_string<n>’
constexpr fixed_string(fixed_string<n> const& s) {
                       ^~~~~~~~~~~~
note:   template argument deduction/substitution failed:
note:   mismatched types ‘const fixed_string<n>’ and ‘fixed_string<...auto...>’

Cool. Итак, <...auto...> - это G CC speak для «Заполнителя выведения шаблона класса» , и я не знаю, как заставить компилятор сопоставить это с моими вызовами функций. Кто-нибудь знает, как сюда принудить G CC? Или, в качестве альтернативы, как распространять строковые литералы через иерархию классов?

Интересный факт, передача str.el в шаблон Base приводит к сбою G CC.

1 Ответ

1 голос
/ 13 июля 2020

Это определенно ошибка ag cc. Я испытал это и нашел этот обходной путь:

template<std::size_t n> struct fixed_string {
    consteval fixed_string(char const (&s)[n]) {
        std::copy_n(s, n, this->el);
    }
    consteval fixed_string(const fixed_string<n>& s) = default;
    consteval bool operator==(fixed_string const&) const = default;
    consteval auto operator<=>(fixed_string const&) const = default;
    char el[n];
    static const std::size_t size = n;
};
template<std::size_t n> fixed_string(char const(&)[n])->fixed_string<n>;

template<std::size_t n, fixed_string<n> str>
class BaseImpl {
    public:
        BaseImpl() {
            std::cout << str.el << std::endl;
        }
};

template <fixed_string s>
using Base = BaseImpl<s.size, s>;

template<std::size_t n, fixed_string<n> str>
class DerivedImpl : public BaseImpl<n, str> {
};

template <fixed_string s>
using Derived = DerivedImpl<s.size, s>;

int main(void) {
    Derived<"Hello World"> x;
}

Или, альтернативно,

template<fixed_string str>
class Base {
    public:
        Base() {
            std::cout << str.el << std::endl;
        }
};

template <std::size_t n, fixed_string<n> s>
using BaseWrapper = Base<s>;

template<fixed_string str>
class Derived : public BaseWrapper<str.size, str> {
};

Общая идея состоит в том, чтобы избегать использования выведенного параметра для вывода другого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...