Использование статических переменных-членов constexpr объекта non-constexpr в качестве аргументов шаблона - PullRequest
0 голосов
/ 08 ноября 2019

Я пишу библиотеку, в которой параметры объекта, которые по своей природе являются статическими, встроены в тип с использованием нетиповых параметров шаблона. Это обеспечивает массовую оптимизацию производительности по сравнению с реализацией, где эти значения являются значениями времени выполнения (небольшие тесты, измеренные в 10 раз, ожидаемые в 5-7 раз). Однако я считаю, что C ++ не очень хорошо поддерживает эту идиому. Я пытаюсь реорганизовать библиотеку, чтобы упростить ее использование разработчиками, которые не очень знакомы с шаблонами или метапрограммированием.

Я хотел бы предложить constexpr функции, которые упрощают извлечение элемента static constexprпеременные (которые используются для распространения статических значений через типы), так что пользователи могут выполнять некоторые базовые метапрограммирования, не понимая тяжелой техники за кулисами. Например,

#include <type_traits>


template <int A, int B>
class Example {
public:
    static constexpr auto C = A + B;
private:
    int b {0};
};

template <int A, int B>
constexpr auto getC(Example<A, B> e) { return decltype(e)::C; }

/**** USER CODE ****/

int main()
{
    Example<1, 2> e;
    Example<2, getC(e)> f;
}

Это не работает, e, не являющийся constexpr, может использоваться в контексте constexpr, даже если вы не используете значение (странно, если Example не имел времени выполненияЧлены, это будет работать). Вместо этого можно было бы написать decltype(e)::C, но если это ссылка, они должны были бы std::remove_reference<decltype(C)>::type::C, и, конечно, они должны были бы знать, чтобы сделать это, и знать достаточно, чтобы обойти общие проблемы, такие как вызов remove_reference. И в этот момент мы отключены для типичного программиста, для которого предназначена эта библиотека.

constexpr функции не работают, макросы не работают с системой типов, поэтому их также недостаточно,как еще я мог это сделать?

Ответы [ 2 ]

1 голос
/ 08 ноября 2019

Я выбрал комбинацию ответа Натана и удаленного ответа для реализации getC.

template <typename T, typename = std::void_t<decltype(std::remove_reference_t<T>::C)>>
constexpr int getC_() { return std::remove_reference_t<T>::C; }

#define getC(e) (getC_<decltype(e)>())

Функция выполняет тяжелую работу и выдает хорошее сообщение об ошибке, если вы дадитеэто недопустимый тип благодаря охране. И макрос выполняет грязный (для начинающего) вызов таким образом, что никогда не сможет потерпеть неудачу сам по себе.

getC(1);  // error: 'C' is not a member of 'std::remove_reference<int>::type' {aka 'int'}
1 голос
/ 08 ноября 2019

Вы можете использовать макрос для переноса

std::remove_reference<decltype(C)>::type::C

Это будет выглядеть как

#define getC(obj) std::remove_reference_t<decltype(obj)>::C
...