请考虑以下代码:
#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;
}
对于x(非常量),没有问题。但即使在编译时知道if / else中的条件,y(const数据类型)也会导致错误。
是否有可能在编译时不编译错误条件?
答案 0 :(得分:11)
最简单的修复是部分模板专业化:
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; }
};
另一个选择是委托:
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是另一种选择,但在这种情况下通常不是首选:
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;
};
答案 1 :(得分:5)
您可以专门为const类型
创建类template<typename T>
class MyClass
{
// Whatever you need to do
};
template<typename T>
class MyClass<const T>
{
// Whatever you need to do for const types
};
答案 2 :(得分:3)
为给定类型编译类模板。即使控制流没有进入赋值,也会编译该赋值。由于成员是const,编译将失败。
您可以使用某种形式的SFINAE来跳过该作业,但它不会像现在一样有效。
这很有用(为简单起见,我删除了testTernary
成员函数):
#include <iostream>
#include <type_traits>
template<typename T> class MyClass
{
public:
MyClass() : myVar{0} {;}
template<class U = T>
typename std::enable_if<std::is_const<U>::value>::type testIf() {
myVar;
}
template<class U = T>
typename std::enable_if<!std::is_const<U>::value>::type testIf() {
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();
y.testIf();
return 0;
}
答案 3 :(得分:1)
如果没有编译else分支,那么你的函数将具有完全不同的含义。您不能只编译部分代码。如果您不希望它执行,请不要写它。它不像每次调用函数时都单独编译。
类型系统的重点是避免意外尝试分配const
变量等事情。您必须编写一个不分配给该变量的全新(或重载)函数。
答案 4 :(得分:0)
试试这个:
template<typename T>
class MyClass
{
T myVar;
public:
MyClass() : myVar(0) {}
void testIf()
{
assign(myVar, 3);
}
private:
template<typename V>
void assign(V& destination, int value)
{
destination = value;
}
template<typename V>
void assign(const V& destination, int value)
{
}
};
答案 5 :(得分:0)
C ++ 17 constexpr if
哦,是的,它已经到了:
main.cpp
#include <cassert>
#include <type_traits>
template <class T>
struct MyClass {
int myFunc() {
if constexpr(std::is_integral<T>())
return 1;
else
return 2;
}
};
int main() {
assert(MyClass<int>().myFunc() == 1);
assert(MyClass<float>().myFunc() == 2);
}
编译并运行:
g++-8 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
另请参阅:Difference between "if constexpr()" Vs "if()"
在Ubuntu 16.04 GCC 8.1.0中进行了测试。