My program defines an Animal
struct that can be configured with CanSwim/CanNotSwim
and 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;
}
Now how do I set a rule to automatically double CanBark::volume
when an Animal
is configured with class CanNotSwim
(in compilation time)? To have:
auto dog = Animal<CanSwim, CanBark>();
dog.bark();
// "bark at volume 10"
auto cat = Animal<CanNotSwim, CanBark>();
cat.bark();
// "bark at volume 20"
I don't intend to move function bark()
from CanBark
to Animal
.
With CRTP, you might got that information:
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();
}
As alternative, you might provide the information in constructor:
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();
}