Is there a way in c++ to get a different overload called based on the runtime/compile time constness of an input? My version(12) of MSVC can\'t do this using constexpr. Reading
To elaborate on my comment, you can try this to work around the limitation you're facing:
Run It Online
#include <iostream>
using std::cout;
using std::endl;
template <int n>
constexpr int Flip4() {
return ((n & 0xFF) << 24) | ((n & 0xFF00) << 8) | ((n & 0xFF0000) >> 8) | ((n & 0xFF000000) >> 24);
}
inline int Flip4(int n) {
return _byteswap_ulong(n);
}
int main() {
constexpr int a = Flip4<0xabcd>(); // calc at compile time
int b = Flip4(0xabcd); // calc at runtime
static_assert(a == -844431360, "");
cout << "a: " << a << endl;
cout << "b: " << b << endl;
}
EDIT: Don't lose hope! User-defined literals are here to the rescue :)
Run It Online
#include <iostream>
using std::cout;
using std::endl;
// wraps a single integer (unsigned long long) in order to use it in a user-defined literal
// the type (unsigned long long) is a limitation of the standard: https://stackoverflow.com/a/16596909/865719
struct IntegerWrapper
{
const unsigned long long value;
constexpr explicit IntegerWrapper(unsigned long long val) : value{val} {}
};
// user-defined literal
constexpr IntegerWrapper operator "" _iw (const unsigned long long value)
{
return IntegerWrapper{value};
}
constexpr int Flip4(IntegerWrapper&& n) {
return ((n.value & 0xFF) << 24) | ((n.value & 0xFF00) << 8) | ((n.value & 0xFF0000) >> 8) | ((n.value & 0xFF000000) >> 24);
}
inline int Flip4(int n) {
return _byteswap_ulong(n);
}
int main() {
constexpr int a = Flip4(0xabcd_iw); // calc at compile time
const int b = Flip4(0xabcd); // calc at runtime
static_assert(a == -844431360, "");
cout << "a: " << a << endl;
cout << "b: " << b << endl;
}
constexpr
can only be applied to variables and functions, but not function parameters (details on cppreference). Furthermore, you cannot overload the function on whether it is computed at compile or run-time, i.e. this is not valid:
constexpr int Flip4(int n) {
return ((n & 0xFF) << 24) | ((n & 0xFF00) << 8) | ((n & 0xFF0000) >> 8) | ((n & 0xFF000000) >> 24);
}
inline int Flip4(int n) {
return _byteswap_uint64(n);
}
One way is to give the functions different names and call them accordingly.
Just as a side note,
A
constexpr
specifier used in a function declaration impliesinline
.
So you don't need to declare your constexpr
function inline
Also, don't forget that constexpr
functions are only guaranteed to be evaluated at compile-time if they are used in a context required at compile time. So to force it you would need to write:
constexpr int a = Flip4('abcd');
Your code is illegal.
[C++11, dcl.constexpr] The
constexpr
specifier shall be applied only to the definition of a variable, the declaration of a function or function template, or the declaration of a static data member of a literal type (3.9). ... [ Note: Function parameters cannot be declared constexpr. — end note ]
constexpr
doesn't even exist in MSVC 2013, so you couldn't try it even if you wanted to. Also, if you're wondering why the feature isn't allowed, see constexpr overloading.