策略库设计:有条件地更改策略 class 中的成员变量
policy base design: conditionally change a member variable from policy class
我的程序定义了一个 Animal
结构,可以用 CanSwim/CanNotSwim
和 CanBark/CanNotBark
:
配置
#include <iostream>
struct CanSwim {
};
struct CanNotSwim {
};
struct CanBark {
CanBark() : volume(10) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) {
volume = newVolume;
}
private:
int volume;
};
struct CanNotBark {
};
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal() = default;
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
return 0;
}
现在,当 Animal
配置为 class CanNotSwim
(在编译时)时,如何设置规则自动加倍 CanBark::volume
?拥有:
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
// "bark at volume 10"
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
// "bark at volume 20"
我不打算将函数 bark()
从 CanBark
移动到 Animal
。
使用 CRTP,您可能会得到以下信息:
struct CanSwim {};
struct CanNotSwim {};
template <typename Der>
struct CanBark {
CanBark() : volume(std::is_base_of_v<CanNotSwim, Der> ? 20 : 10) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) { volume = newVolume; }
private:
int volume;
};
template <typename Der>
struct CanNotBark {};
template<class SwimType, template <typename> class BarkType>
struct Animal : public SwimType, public BarkType<Animal<SwimType, BarkType>> {
Animal() = default;
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
}
或者,您可以在构造函数中提供信息:
struct CanSwim {};
struct CanNotSwim {};
struct CanBark {
CanBark(bool canSwim) : volume(canSwim ? 10 : 20) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) { volume = newVolume; }
private:
int volume;
};
struct CanNotBark {
CanNotBark(bool canSwim) {}
};
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal() : BarkType(std::is_same_v<SwimType, CanSwim>) {}
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
}
嗯...简单地修改 Animal
构造函数以使用正确的值调用 setVolume()
(如果 BarkType
是 CanBark
)怎么样?
我的意思是……
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal ()
{
if constexpr ( std::is_same_v<BarkType, CanBark> )
BarkType::setVolume(std::is_same_v<SwimType, CanNotSwim> ? 20 : 10);
}
};
这显然至少需要 C++17(if constexpr
在 C++17 中引入)或 setVolume()
调用在 CanNotBark
情况下给出错误。在 C++17 之前,您必须使用 SFINAE 来 activate/disactivate 两个不同的构造函数。
否则,如果您在构造时直接在 CanBark
中需要正确的音量值,则必须将信息作为模板参数传递,如 Jarod42 的答案所示。
我的程序定义了一个 Animal
结构,可以用 CanSwim/CanNotSwim
和 CanBark/CanNotBark
:
#include <iostream>
struct CanSwim {
};
struct CanNotSwim {
};
struct CanBark {
CanBark() : volume(10) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) {
volume = newVolume;
}
private:
int volume;
};
struct CanNotBark {
};
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal() = default;
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
return 0;
}
现在,当 Animal
配置为 class CanNotSwim
(在编译时)时,如何设置规则自动加倍 CanBark::volume
?拥有:
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
// "bark at volume 10"
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
// "bark at volume 20"
我不打算将函数 bark()
从 CanBark
移动到 Animal
。
使用 CRTP,您可能会得到以下信息:
struct CanSwim {};
struct CanNotSwim {};
template <typename Der>
struct CanBark {
CanBark() : volume(std::is_base_of_v<CanNotSwim, Der> ? 20 : 10) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) { volume = newVolume; }
private:
int volume;
};
template <typename Der>
struct CanNotBark {};
template<class SwimType, template <typename> class BarkType>
struct Animal : public SwimType, public BarkType<Animal<SwimType, BarkType>> {
Animal() = default;
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
}
或者,您可以在构造函数中提供信息:
struct CanSwim {};
struct CanNotSwim {};
struct CanBark {
CanBark(bool canSwim) : volume(canSwim ? 10 : 20) {}
void bark() {
std::cout << "bark at volume " << volume << std::endl;
}
void setVolume(int newVolume) { volume = newVolume; }
private:
int volume;
};
struct CanNotBark {
CanNotBark(bool canSwim) {}
};
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal() : BarkType(std::is_same_v<SwimType, CanSwim>) {}
};
int main() {
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
}
嗯...简单地修改 Animal
构造函数以使用正确的值调用 setVolume()
(如果 BarkType
是 CanBark
)怎么样?
我的意思是……
template<class SwimType, class BarkType>
struct Animal : public SwimType, public BarkType {
Animal ()
{
if constexpr ( std::is_same_v<BarkType, CanBark> )
BarkType::setVolume(std::is_same_v<SwimType, CanNotSwim> ? 20 : 10);
}
};
这显然至少需要 C++17(if constexpr
在 C++17 中引入)或 setVolume()
调用在 CanNotBark
情况下给出错误。在 C++17 之前,您必须使用 SFINAE 来 activate/disactivate 两个不同的构造函数。
否则,如果您在构造时直接在 CanBark
中需要正确的音量值,则必须将信息作为模板参数传递,如 Jarod42 的答案所示。