Перегрузка по constexpr
От: _NN_ www.nemerleweb.com
Дата: 23.08.18 11:18
Оценка:
Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?
Например:

template<typenmae T>
auto f(T const& t)
{
  return 1;
}

constexpr auto f(int t) // для int constexpr, для остальных нет
{
  return 2;
}


Я хочу написать функцию g с различным поведением, псевдокод
template<int V> struct Integer { static const int value = V + 10; }


template<typenmae T>
auto g(T const& t)
{
  if compiletime (f(t))
  {
    return Integer<f(t)>();
  }
  else
  {
    return f(t) + 20;
  }
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Перегрузка по constexpr
От: vopl Россия  
Дата: 23.08.18 12:01
Оценка: 46 (2)
Здравствуйте, _NN_, Вы писали:

_NN>Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?

_NN>Например:

_NN>
_NN>template<typenmae T>
_NN>auto f(T const& t)
_NN>{
_NN>  return 1;
_NN>}

_NN>constexpr auto f(int t) // для int constexpr, для остальных нет
_NN>{
_NN>  return 2;
_NN>}
_NN>


_NN>Я хочу написать функцию g с различным поведением, псевдокод

_NN>
_NN>template<int V> struct Integer { static const int value = V + 10; }


_NN>template<typenmae T>
_NN>auto g(T const& t)
_NN>{
_NN>  if compiletime (f(t))
_NN>  {
_NN>    return Integer<f(t)>();
_NN>  }
_NN>  else
_NN>  {
_NN>    return f(t) + 20;
_NN>  }
_NN>}
_NN>


Можно на основе SFINAE определить, является ли f constexpr для заданного T, примерно так
Re[2]: Перегрузка по constexpr
От: _NN_ www.nemerleweb.com
Дата: 23.08.18 13:30
Оценка:
Здравствуйте, vopl, Вы писали:

  if constexpr (is_f_constexpr_for<T>(0))
  {
    return Integer<f(0)>::value;// внимание, константа вместо t
  }


А как воспользоваться результатом f(t), чтобы было во времени компиляции ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Перегрузка по constexpr
От: vopl Россия  
Дата: 23.08.18 16:18
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, vopl, Вы писали:


_NN>
_NN>  if constexpr (is_f_constexpr_for<T>(0))
_NN>  {
_NN>    return Integer<f(0)>::value;// внимание, константа вместо t
_NN>  }
_NN>


_NN>А как воспользоваться результатом f(t), чтобы было во времени компиляции ?


Для этого надо чтобы значение t было компайл-тайм константой, например так
Отредактировано 24.08.2018 9:47 vopl . Предыдущая версия . Еще …
Отредактировано 24.08.2018 9:37 vopl . Предыдущая версия .
Re: Перегрузка по constexpr
От: nikov США http://www.linkedin.com/in/nikov
Дата: 23.08.18 18:41
Оценка: 46 (4)
Здравствуйте, _NN_, Вы писали:

_NN>Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?


Можно сделать макрос, который будет вызывать различные реализации функции в зависимости от того, являются ли аргументы константами времени компиляции, примерно так: https://stackoverflow.com/a/40413051/305118
Re[2]: Перегрузка по constexpr
От: nikov США http://www.linkedin.com/in/nikov
Дата: 23.08.18 19:12
Оценка:
Здравствуйте, nikov, Вы писали:

_NN>>Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?


N>Можно сделать макрос, который будет вызывать различные реализации функции в зависимости от того, являются ли аргументы константами времени компиляции, примерно так: https://stackoverflow.com/a/40413051/305118


Ещё можно посмотреть, как устроен BOOST_HANA_ASSERT:

Expands to the strongest form of assertion possible for the given condition. Given a condition, BOOST_HANA_ASSERT expands either to a compile-time or to a runtime assertion, depending on whether the value of the condition is known at compile-time or at runtime.


Из boost/hana/assert.hpp:
#   define BOOST_HANA_ASSERT(...)                                           \
        BOOST_HANA_CHECK(__VA_ARGS__)                                       

//...

#   define BOOST_HANA_CHECK(...)                                            \
        BOOST_HANA_CHECK_MSG(                                               \
            (__VA_ARGS__),                                                  \
            BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
        )                                                                   

// ...

#   define BOOST_HANA_CHECK_MSG(condition, message)                         \
    do {                                                                    \
        auto __hana_tmp = condition;                                        \
        ::boost::hana::if_(::boost::hana::bool_c<                           \
            ::boost::hana::Constant<decltype(__hana_tmp)>::value>,          \
            [](auto expr) {                                                 \
                static_assert(::boost::hana::value<decltype(expr)>(),       \
                message);                                                   \
            },                                                              \
            [](auto expr) {                                                 \
                if (!static_cast<bool>(expr)) {                             \
                    ::std::fprintf(stderr, "Assertion failed: "             \
                        "(%s), function %s, file %s, line %i.\n",           \
                        message, __func__, __FILE__, __LINE__);             \
                    ::std::abort();                                         \
                }                                                           \
            }                                                               \
        )(__hana_tmp);                                                      \
    } while (false);                                                        \
    static_assert(true, "force trailing semicolon")
Re[4]: Перегрузка по constexpr
От: vopl Россия  
Дата: 24.08.18 09:48
Оценка:
Здравствуйте, vopl, Вы писали:

_NN>>А как воспользоваться результатом f(t), чтобы было во времени компиляции ?


V>Для этого надо чтобы значение t было компайл-тайм константой, например так


[добавка]
либо, если домен значений t не велик — можно построить транслятор из рантайма в компайл-тайм, примерно так

template<typenmae T>
auto g(T const& t)
{
  if(is_f_constexpr_for<T>())
  {
    switch(t)
    {
      case 0: return Integer<f(0)>::value;
      case 1: return Integer<f(1)>::value;
      case 2: return Integer<f(2)>::value;
      case 3: return Integer<f(3)>::value;
      default:
        //throw "случилось плохое значение t, для него нет компайл-тайм реализации";
        return f(t) + 20;
    }
  }
  else
  {
    return f(t) + 20;
  }
}
Re[2]: Перегрузка по constexpr
От: rg45 СССР  
Дата: 25.08.18 13:24
Оценка:
Здравствуйте, vopl, Вы писали:

V>Можно на основе SFINAE определить, является ли f constexpr для заданного T, примерно так


Что-то я не очень понимаю, какую задачу ты решал. Любое выражение типа int у тебя обрабатывается как constexpr, даже если оно таковым не является:
здесь. Такого же поведения можно было добиться обычной перегрузкой для типа int без всякого SFINAE. Но, как я понимаю, это не то, чего ждал ТС.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.08.2018 14:39 rg45 . Предыдущая версия . Еще …
Отредактировано 25.08.2018 13:34 rg45 . Предыдущая версия .
Re: Перегрузка по constexpr
От: rg45 СССР  
Дата: 25.08.18 13:29
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>Я хочу написать функцию g с различным поведением, псевдокод

_NN>
_NN>template<int V> struct Integer { static const int value = V + 10; }


_NN>template<typenmae T>
_NN>auto g(T const& t)
_NN>{
_NN>  if compiletime (f(t))
_NN>  {
_NN>    return Integer<f(t)>();
_NN>  }
_NN>  else
_NN>  {
_NN>    return f(t) + 20;
_NN>  }
_NN>}
_NN>


Насколько я знаю, невозможно внутри функции определить каким выражением был сформирован фактический параметр (constexpr/non-constexpr), это можно сделать только "снаружи", в точке вызова. Поэтому здесь лучше сразу смотреть в сторону подхода, предложенного Nikov.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.08.2018 13:36 rg45 . Предыдущая версия . Еще …
Отредактировано 25.08.2018 13:35 rg45 . Предыдущая версия .
Re[2]: Перегрузка по constexpr
От: _NN_ www.nemerleweb.com
Дата: 26.08.18 06:48
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, _NN_, Вы писали:


_NN>>Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?


N>Можно сделать макрос, который будет вызывать различные реализации функции в зависимости от того, являются ли аргументы константами времени компиляции, примерно так: https://stackoverflow.com/a/40413051/305118


Спасибо.
Мне по сути нужно только поменять возвращаемый тип (продолжение топика с std::array::size
Возможно тут будет вариант попроще?

Или хотя бы макрос не выставлять наружу, а только внутри size_smallest.

template<unsigned long long Value>
constexpr auto size_smallest_type()
{
 // возвращаем наименьший тип в который влезает Value.
}

template<typename Container>
auto size_smallest(Container const& container)
{
  if constexpr-expression std::size(container)
  {
    return size_smallest_type<std::size(container)>(); // Возвращаемый тип будет наименьшим необходимым
  }
  else
  {
    return std::size(container); // Возвращаемый тип будет size_t
  }
}

// Используем
DWORD WINAPI GetModuleFileName(
  _In_opt_ HMODULE hModule,
  _Out_    LPTSTR  lpFilename,
  _In_     DWORD   nSize
);

std::array<char, 100> buf;
GetModuleFileName(nullptr, std::data(buf), size_smallest(buf)); // нет проблем с компиляцией, т.к. size_smallest(buf) имеет тип unsigned char


P.S.
Самый трепещущий всех вопрос, почему господин nikov занимается плюсами ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Перегрузка по constexpr
От: vopl Россия  
Дата: 26.08.18 19:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>Можно на основе SFINAE определить, является ли f constexpr для заданного T, примерно так


R>Что-то я не очень понимаю, какую задачу ты решал.

определить, является ли "f(чето)" — constexpr выражением

R>Любое выражение типа int у тебя обрабатывается как constexpr, даже если оно таковым не является:
здесь.
хм.. Плохой пример? В нем вижу буквально следующее

constexpr auto f(int) // для int constexpr, для остальных нет

То есть, не показана ситуация "даже если оно таковым не является"

>>Такого же поведения можно было добиться обычной перегрузкой для типа int без всякого SFINAE. Но, как я понимаю, это не то, чего ждал ТС.

давай я уберу constexpr для int и повставляю его для тругих типов здесь
Re[4]: Перегрузка по constexpr
От: rg45 СССР  
Дата: 26.08.18 19:11
Оценка:
Здравствуйте, vopl, Вы писали:

V>хм.. Плохой пример? В нем вижу буквально следующее

V>

constexpr auto f(int) // для int constexpr, для остальных нет

V>То есть, не показана ситуация "даже если оно таковым не является"

Как это не показана? Фактический параметр (i) функции g здесь не является constexpr выражением:

int main()
{
    int i;
    std::stringstream input("42"); 
    input >> i;
    
    std::cout << g(i) << std::endl; // output: 12
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Перегрузка по constexpr
От: nikov США http://www.linkedin.com/in/nikov
Дата: 27.08.18 00:38
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>Самый трепещущий всех вопрос, почему господин nikov занимается плюсами ?


Потому что с марта 2017 я работаю в Synopsys, Coverity Analysis, пишу статический анализ для плюсов (и для других языков), на плюсах. Потихоньку зубрю Стандарт C++
Re[5]: Перегрузка по constexpr
От: vopl Россия  
Дата: 27.08.18 08:52
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>хм.. Плохой пример? В нем вижу буквально следующее

V>>

constexpr auto f(int) // для int constexpr, для остальных нет

V>>То есть, не показана ситуация "даже если оно таковым не является"

R>Как это не показана? Фактический параметр (i) функции g здесь не является constexpr выражением:


R>
R>int main()
R>{
R>    int i;
R>    std::stringstream input("42"); 
R>    input >> i;
    
R>    std::cout << g(i) << std::endl; // output: 12
R>}
R>


А.. понял о чем ты. Задача, которую я решал звучит так: "определить, является ли конкретная перегрузка "R f(T)" — constexpr функцией". Ты же приводишь немного другой кейс, "определить, является ли поданное (извне) значение/выражение — компайл-тайм константой". Согласен, что твой аспект так же является актуальным в оригинальном вопросе ТС.

По твоему кейсу — согласен с твоим же высказыванием отсюда
Автор: rg45
Дата: 25.08.18
. Единственное что могу добавить — это привести известный мне способ определения константности выражения:
  код
#include <iostream>

constexpr auto makeprval(auto && t)
{
  return t;
}

#define isprvalconstexpr(e) noexcept(makeprval(e))


template<typename T>
constexpr auto g(T t)
{
    if constexpr (isprvalconstexpr(t))//вариант "внутри" - это не сработает, тут будет всегда ложь
    {
        std::cout<<"g(t): ct"<<std::endl;
        return t+10;
    }
    else
    {
        std::cout<<"g(t): rt"<<std::endl;
        return t;
    }
}

int main()
{
    {
        g(10);

        int rti = 10;
        g(rti);
    }

    {
        constexpr int t = 220;  //ct
        //enum {t=220};         //ct
        //int t = 220;          //rt

        if constexpr (isprvalconstexpr(t))//вариант "снаружи" - работает нормально
        {
            std::cout<<"ct"<<std::endl;
        }
        else
        {
            std::cout<<"rt"<<std::endl;
        }
    }

    return 0;
}


Ну и конечно, ТС-у надо бы рассмотреть вариант предложенный nikov, поковырять boost hana, может там как то по другому это селано.
Re: Перегрузка по constexpr
От: nikov США http://www.linkedin.com/in/nikov
Дата: 04.09.18 00:46
Оценка: 28 (2)
Здравствуйте, _NN_, Вы писали:

_NN>Возможно ли делать разные действия в зависимости от возможности получения значения во времени компиляции ?


Кстати, я нашел два документа, касающихся этого вопроса. Там предлагаются изменения в c++, которые позволили бы делать это более естественным и удобным образом:

The `constexpr` Operator (P0595)
`constexpr` Function Parameters (P1045R0)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.