Здравствуйте, watchmaker, Вы писали:
W>Требуется же поддержка в компиляторе. Например, через __builtin_is_constant_evaluated как в gcc и clang.
С одной стороны я догадывался, а с другой эта фича задекларирована как расширение библиотеки. По-этому была надежда, вдруг это можно с помощью шаблонной магии разрулить и я что-то упускаю.
W>Пока только дать программисту две функции и попросить самому выбрать нужную: W>
W>constexpr int constexpr_add(int a, int b);
W>int runtime_add(int a, int b);
W>
К сожалению не получается, т.к. у меня может быть куча вложенных constexpr-методов или конструкторов и где-то внутри вот такой вот constexpr_add/runtime_add. Т.е. придется дублировать разные методы, а главное классы выше по иерархии, и так как методы с constexpr и без нельзя перегрузить, код перестанет компилироваться одно с другим.
Здравствуйте, Videoman, Вы писали:
V>К сожалению не получается, т.к. у меня может быть куча вложенных constexpr-методов или конструкторов и где-то внутри вот такой вот constexpr_add/runtime_add. Т.е. придется дублировать разные методы, а главное классы выше по иерархии, и так как методы с constexpr и без нельзя перегрузить, код перестанет компилироваться одно с другим.
А не получится ли параметризовать все дерево вычислений режимом (компайл- ран- тайи)? Как-то так:
#include <iostream>
int __intrinsic_add(int a, int b) { std::cout << "intrinsic_add: " << std::endl; return a + b; }
enum class ComputationMode {
RunTime,
CompileTime,
};
template <ComputationMode>
int add(int a, int b) { return __intrinsic_add(a, b); }
template <>
constexpr int add<ComputationMode::CompileTime>(int a, int b) { return a + b; }
template <ComputationMode mode>
constexpr int compute(int a, int b) { return add<mode>(a, b); }
int main()
{
std::cout << compute<ComputationMode::RunTime>(2, 3) << std::endl;
std::cout << compute<ComputationMode::CompileTime>(2, 3) << std::endl;
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>А не получится ли параметризовать все дерево вычислений режимом (компайл- ран- тайи)? Как-то так:
Не уверен что мне подойдет, но в плане обсуждения идеи: я вижу что у вас все-равно явно придется параметризовать ComputationMode::RunTime или ComputationMode::CompileTime, а мне нужно делать это автоматически, т.к. в случае compile-time в С++17 нельзя использовать instrinsic, а в случае runtime — как-раз эффективнее использовать instrinsic. Я не вижу здесь автоматизации выбора той или иной реализации в зависимости от того в каком режиме собирается код.
#include <type_traits>
#include <cstdio>
#define UTILITY_CONSTEXPR(exp) (::utility::constexpr_bool<(exp) ? true : false>::value)
#ifndef __clang__
#define UTILITY_IS_CONSTEXPR_VALUE(...) UTILITY_CONSTEXPR(noexcept(::utility::makeprval((__VA_ARGS__, 0))))
#else
#define UTILITY_IS_CONSTEXPR_VALUE(...) UTILITY_CONSTEXPR(__builtin_constant_p((__VA_ARGS__, 0))) // can be used for the GCC too#endif
namespace utility
{
// to suppress `warning C4127: conditional expression is constant`template <bool B, typename...>
struct constexpr_bool
{
static constexpr const bool value = B;
};
template <bool B, typename... types>
const bool constexpr_bool<B, types...>::value;
// remove_reference + remove_cvtemplate <typename T>
struct remove_cvref
{
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
// CAUTION:
// Return values in the `makeprval` are required to avoid breakage in the `Visual Studio 2015 Update 3` compiler.
//template <typename T>
constexpr typename remove_cvref<T>::type makeprval(T && v)
{
return v;
}
// static array type must be overloaded separately, otherwise will be an error: `error: function returning an array`template <typename T>
constexpr const typename remove_cvref<T>::type & makeprval(const T & v)
{
return v;
}
}
inline int myintrinsic_add(int a, int b)
{
return a + b + 1;
}
template <bool is_constexpr>
struct t_optimized_add
{
constexpr int operator()(int a, int b) const
{
return a + b;
}
};
template <>
struct t_optimized_add<false>
{
int operator()(int a, int b) const
{
return myintrinsic_add(a, b);
}
};
#define OPTIMIZED_ADD(a, b) \
t_optimized_add<UTILITY_IS_CONSTEXPR_VALUE(t_optimized_add<true>()(a, b))>()(a, b)
static int a = 100;
int main()
{
printf("%d\n", OPTIMIZED_ADD(1, 1));
printf("%d\n", OPTIMIZED_ADD(a, 1));
}
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions.
Любое не констекспр выражение может потенциально кинуть эксепшен.
Под "is declared to not throw any exceptions" имеется ввиду и просто код или выражение, которое никто заранее конечно не декларировал как expect или noexcept.
Отсюда, видимо, и танцы.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Любое не констекспр выражение может потенциально кинуть эксепшен. V>Под "is declared to not throw any exceptions" имеется ввиду и просто код или выражение, которое никто заранее конечно не декларировал как expect или noexcept. V>Отсюда, видимо, и танцы.
Здравствуйте, Videoman, Вы писали: V>>Любое не констекспр выражение может потенциально кинуть эксепшен. V>>Под "is declared to not throw any exceptions" имеется ввиду и просто код или выражение, которое никто заранее конечно не декларировал как expect или noexcept. V>>Отсюда, видимо, и танцы. V>Ну как-то не очень надежно. А если декларировал?
А в чём проблема?
Здравствуйте, Videoman, Вы писали:
V>>А в чём проблема? V>Да нет проблем. Просто с детства не люблю макросы и то как они "протекают" между пространствами имен.
Ну так используй новый стандарт.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]