Ошибка подстановки аргумента шаблона с C-строкой в качестве нетипичного параметра шаблона
Я пытаюсь создать тип, который позволил бы мне сделать что-то вроде этого:
constexpr const char x[] = "x";
constexpr const char y[] = "y";
int main()
{
Type<_Type<int, x>, _Type<float, y> > truc;
std::cout << truc.get<std::forward<const char*>(x)>() << std::endl;
}
_Type
(который будет переименован) должен содержать код для получения данных (используя параметры шаблона) из базы данных (переменная-член является статической, потому что такие тесты было проще выполнять). Type
(который тоже будет переименован) используется для связывания _Type
,
С x
а также y
как локальная переменная, gcc
Говорит, что x
а также y
не имеют связи.
Реализация типа:
constexpr bool strings_equal(char const* a , char const* b )
{
return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1));
}
template <typename T, const char* n>
struct _Type {
using type = T;
static constexpr T value = T{};
static constexpr const char* name = n;
template <const char* name, typename = typename std::enable_if<strings_equal(n, name)>::value>
T get()
{
return value;
}
};
template <typename T>
struct _Type2 : T {
};
template <class... T>
struct Type {
std::tuple<T...> vals;
template <unsigned idx, const char* name, bool end_ = true>
auto _get() -> typename decltype(std::get<idx + 1>(vals))::type
{
return decltype(std::get<idx + 1>(vals))::value;
}
template <unsigned idx, const char* name, bool end_>
auto _get() -> decltype(
_get<(idx + 1), std::forward<const char*>(name), strings_equal(name, std::remove_reference<decltype(std::get<idx + 1>(vals))>::type::name)>())
{
return _get<idx + 1, std::forward<const char*>(name), string_equal(name, std::remove_reference<decltype(std::get<idx + 1>(vals))>::type::name)>;
}
template <const char* name>
auto get() -> decltype(
_get<0, std::forward<const char*>(name), strings_equal(name, std::remove_reference<decltype(std::get<0>(vals))>::type::name)>())
{
return _get<0, name, string_equal(std::forward<const char*>(name), decltype(std::get<0>(vals))::name)>;
}
};
Этот код выдает ошибку (во время компиляции).
clang
дает мне эту ошибку:
test.cpp:60:23: error: no matching member function for call to 'get'
std::cout << truc.get<std::forward<const char*>(x)>() << std::endl;
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:48:10: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'name'
auto get() -> decltype(
^
1 error generated.
Полный код и gcc
ошибка доступна здесь.
Что я могу сделать, чтобы устранить эту ошибку и иметь возможность использовать локальную переменную для нетипичного параметра шаблона?
Спасибо за ответ.
РЕДАКТИРОВАТЬ Использование локальной строки не будет работать из-за их связи (спасибо @PasserBy за объяснение)
РЕДАКТИРОВАТЬ 2 Решено, благодаря @Jarod42
1 ответ
Локальные переменные никогда не могут иметь внешних связей. Когда-либо. Относительно того, почему связь важна, посмотрите это.
Суть в том, что только c-строки внешней связи имеют одинаковое значение в единицах перевода, и только тогда параметр будет одинаковым для всех единиц перевода.
Следующий код компилируется
constexpr const char x[] = "x";
constexpr const char y[] = "y";
template<typename T, typename U>
struct Type {};
template<typename T, const char*>
struct _Type {};
int main()
{
//good, external linkage
Type<_Type<int, x>, _Type<float, y>> t1;
//won't compile, string literal has internal linkage
//Type<_Type<int, "x">, _Type<float, "y">> t2;
static constexpr const char local[] = "x";
//won't compile, local variables don't have external linkage
//Type<_Type<int, local>, _Type<float, local>> t3;
}