Consider the following code :
#include <iostream> #include <type_traits> template<typename T> class MyClass { public: MyClass() : myVar{0} {;} void testIf() { if (isconst) { myVar; } else { myVar = 3; } } void testTernary() { (isconst) ? (myVar) : (myVar = 3); } protected: static const bool isconst = std::is_const<T>::value; T myVar; }; int main() { MyClass<double> x; MyClass<const double> y; x.testIf(); x.testTernary(); y.testIf(); // <- ERROR y.testTernary(); // <- ERROR return 0; }
For x (non-const) there is no problem. But y (const data type) cause an error even if the condition in if/else is known at compile-time.
Is there any possibility to not compile the false condition at compile-time ?
C++17 if constexpr
Oh yes, it has arrived:
main.cpp
#include <cassert> #include <type_traits> template<typename T> class MyClass { public: MyClass() : myVar{0} {} void modifyIfNotConst() { if constexpr(!isconst) { myVar = 1; } } T myVar; protected: static constexpr bool isconst = std::is_const<T>::value; }; int main() { MyClass<double> x; MyClass<const double> y; x.modifyIfNotConst(); y.modifyIfNotConst(); assert(x.myVar == 1); assert(y.myVar == 0); return 0; }
GitHub upstream.
Compile and run:
g++-8 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp ./main.out
See also: Difference between "if constexpr()" Vs "if()"
This will be really cool together with C++20 "string literal template arguments": Passing a string literal as a parameter to a C++ template class
Tested in Ubuntu 16.04, GCC 8.1.0.
The simplest fix is partial template specialization:
template<typename T> class MyClassBase { public: MyClassBase() : myVar{0} {;} protected: T myVar; }; template<typename T> class MyClass: MyClassBase<T> { public: void testIf() { myVar = 3; } }; template<typename T> class MyClass<const T>: MyClassBase<const T> { public: void testIf() { myVar; } };
Another option is delegation:
template<typename T> class MyClass { public: MyClass() : myVar{0} {;} void testIf() { testIf_impl(std::integral_constant<bool, isconst>()); } protected: static const bool isconst = std::is_const<T>::value; T myVar; private: void testIf_impl(std::true_type) { myvar; } void testIf_impl(std::false_type) { myVar = 3; } };
SFINAE is another option, but is generally not preferred for this case:
template<typename T> class MyClass { public: MyClass() : myVar{0} {;} template <typename U = void> typename std::enable_if<std::is_const<T>::value, U>::type testIf() { myvar; } template <typename U = void> typename std::enable_if<!std::is_const<T>::value, U>::type testIf() { myvar = 3; } protected: static const bool isconst = std::is_const<T>::value; T myVar; };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With