Reputation: 1849
I have redefined certain C++ function objects (STL functional) to provide constexpr operator() for them. I needed these functionals to get evaluated at compile time to use for template metaprogramming. C++14 provides constexpr equivalents for the STL functional library. Currently I am compiling code with C++11, but might eventually upgrade to C++14. How do I implement these such that if I upgrade to C++14, it would automatically pick the function objects from STL, rather than my custom implementation.
Here is how I have it so far:
namespace foo {
template <class T = void>
struct less {
constexpr bool operator()(T const& lhs, T const& rhs) const {
return lhs < rhs;
}
};
}
EDIT: I know this could be potentially done with __cplusplus
if I just alias my namespace with std. However that would be a bad solution since I would pollute the namespace foo for all other instances.
Upvotes: 1
Views: 560
Reputation: 20661
You can use the __cplusplus
preprocessor-based solution without polluting the foo
namespace, something along the lines of:
namespace foo {
#if __cplusplus < 201402L
template <class T = void>
struct less {
constexpr bool operator()(T const& lhs, T const& rhs) const {
return lhs < rhs;
}
};
#else
using std::less;
#endif
}
This defines a custom version of foo::less
for C++ versions older than '14, and creates a an alias (still usable as foo::less
) to std::less
for newer C++ versions.
(The constant 201402L
comes from the standard itself. Compilers conforming to C++14 are required to set __cplusplus
to at least this value).
The above code might result in using your custom implementation of less
in cases where the compiler has only partial support for C++14, even if that partial support includes a constexpr
-qualified std::less::operator()
. Apparently this is true for the latest version of Visual Studio. I suggest that this isn't even worth worrying about; calls to the function should be inlined anyway, and the moment you compile with a properly conforming C++14 compiler, you'll get the exact (compilation-level) behavior that you wanted. Alternatively, you could extend the pre-processor logic (i.e. check for compiler-specific macros) to recognize specific compiler versions known to be sufficiently conformant.
Upvotes: 0
Reputation: 145419
Options, with the approach with probably least work and least impact on code, first:
Using the compiler's include file path to choose different versions of a header.
Compiler version sniffing and conditional compilation (e.g. #ifdef
).
Wholesale code editing, possibly automated.
Compiler sniffing is pretty brittle, but is common.
It's generally not enough to just check the value of __cplusplus
.
Using the compiler's include path you would for example first define a header <relops.hpp>
, which just defines or names everything in terms of C++14 functionality, the default implementation, and place that in your regular header include directory.
And via your compiler's include path (e.g. CPATH
for g++, and INCLUDE
for Visual C++), if necessary for the particular compiler, you would direct it to first look for <relops.h>
in some other directory for system-specific headers.
And this <relops.h>
would define things itself, like in your presented code.
With conditional compilation you would instead determine the compiler and version based on macros such as __cplusplus
, _MSC_VER
, __GNUC__
, something for Mac, possibly more. You would define some symbol as a result, e.g. IS_CPP14
. Then you'd use #if IS_CPP14
… #else
… #endif
.
Upvotes: 4