Недопустимый аргумент шаблона, требуется константное выражение времени компиляции
Есть следующая структура классов:
RCC.h
#pragma once
template<auto address>
class Register
{
public:
static void Set(unsigned int value)
{
*reinterpret_cast<unsigned int*>(address) = value;
}
};
template<auto address>
class RCCBase
{
private:
static constexpr auto cr_address = address + 0x00;
static constexpr auto pllcfgr_address = address + 0x04;
public:
struct CR : public Register<cr_address>
{
};
struct PLLCFGR : public Register<pllcfgr_address>
{
};
};
// Только для vs. В IAR подставить конкретный адрес.
extern unsigned int ext_rcc[128];
using RCC = RCCBase<ext_rcc>;
И следующий код:
main.cpp
#include "RCC.h"
// Только для vs
u32 ext_rcc[128] = { 0 };
int main(void)
{
RCC::CR::Set(0);
RCC::PLLCFGR::Set(0);
return 0;
}
Проблема что первая строчка RCC::CR::Set(0); выполняется как положено, а следующая при компиляции создает ошибку: Ошибка C2975 address_: недопустимый аргумент шаблона для "Register", требуется константное выражение времени компиляции
Не понимаю, почему в классе RCCBase cr_address остается константой времени компиляции, pllcfgr_address из-за сложения перестает ею быть. Пробовал такое:
static constexpr auto offset = 0x04;
static constexpr auto pllcfgr_address = address + offset;
Та же самая ошибка. В чем дело-то?
Проект собран как консольное приложение в VS2019 со стандартом C++17
Лог сборки:
Сборка начата…
1>------ Сборка начата: проект: ConsoleApplication2, Конфигурация: Debug x64 ------
1>main.cpp
1>C:\Users\fedorov_dn\source\repos\ConsoleApplication2\ConsoleApplication2\RCC.h(29): error C2975: address: недопустимый аргумент шаблона для "Register", требуется константное выражение времени компиляции
1>C:\Users\fedorov_dn\source\repos\ConsoleApplication2\ConsoleApplication2\RCC.h(3): message : см. объявление "address"
1>C:\Users\fedorov_dn\source\repos\ConsoleApplication2\ConsoleApplication2\main.cpp(9): message : выполняется компиляция ссылки на экземпляр класс шаблон функции "RCCBase<& ext_rcc>::PLLCFGR"
1>Сборка проекта "ConsoleApplication2.vcxproj" завершена с ошибкой.
========== Сборка: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========
Ответы (1 шт):
минимальный воспроизводимый пример:
template<auto x_address>
struct Foo {};
char bar[8]{};
Foo<bar + 0> a{};
Foo<bar + 4> b{};
при сборке с флагами /std:c++17 /permissive- /diagnostics:caret получаем
<source>(6,12): error C2975: 'x_address': invalid template argument for 'Foo', expected compile-time constant expression
Foo<bar + 4> b{};
^
<source>(1): note: see declaration of 'x_address'
template<auto x_address>
По стандарту параметр шаблона не-тип не может ссылаться на подобъект, которым является элемент массива:
[temp.arg.nontype]
2 A template-argument for a non-type template-parameter shall be a converted constant expression (8.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
— (2.1) a subobject (4.5),
— (2.2) a temporary object (15.2),
— (2.3) a string literal (5.13.5),
— (2.4) the result of a typeid expression (8.2.8), or
— (2.5) a predefined func variable (11.4.1).
[intro.object]
2 Objects can contain other objects, called subobjects. A subobject can be a member subobject (12.2), a base class subobject (Clause 13), or an array element.
Что делать? Передавать смещение от базового адреса в качестве еще одного параметра шаблона.