对于模板参数给出的类型,C ++有一些鸭子类型。我们不知道DUCK1
和DUCK2
的类型,但只要它们可以quack()
,它就会编译并运行:
template <class DUCK1, class DUCK2>
void let_them_quack(DUCK1* donald, DUCK2* daisy){
donald->quack();
daisy->quack();
}
但写起来有点不方便。当我完全不关心实际类型DUCK1
和DUCK2
是什么,而是想要完全使用鸭子打字的想法时,那么我想要有一些与上面不同的东西:
C ++是否提供了实现3个创意中的一个或多个的任何功能?
(我知道虚拟继承在大多数情况下是实现这种模式的首选方法,但这里的问题具体是关于静态多态的情况。)
答案 0 :(得分:10)
关于问题1和2:从C ++ 14开始,您可以省略显式template <typename ...
样板并使用auto
,但仅限于lambdas:
auto let_them_quack = [] (auto & donald, auto & daisy){
donald.quack();
daisy.quack();
};
(是的,我更喜欢对指针的引用)。 GCC允许在常规功能中作为扩展。
对于问题3,您所谈论的内容称为 concepts 。它们在C ++中存在了很长时间,但仅作为一个文档术语。现在 Concepts TS 正在进行中,允许您编写类似
的内容template<typename T>
concept bool Quackable = requires(T a) {
a.quack();
};
void let_them_quack (Quackable & donald, Quackable & daisy);
请注意,它还不是C ++,只是正在进行的技术规范。不过,GCC 6.1似乎已经支持它了。使用当前C ++实现概念和约束是可能的;你可以在boost中找到一个。
答案 1 :(得分:5)
我想省略编写重复的模板参数列表 并且大多没有意义(想象一下,如果有7个会发生什么 鸭...)
为此您可以使用可变参数模板并执行以下操作:
template<typename DUCK>
void let_them_quack(DUCK &&d) {
d.quack();
}
template<typename DUCK, typename... Args>
void let_them_quack(DUCK &&d, Args&& ...args) {
d.quack();
let_them_quack(std::forward<Args>(args)...);
}
答案 2 :(得分:1)
class duck {
public:
virtual void quack()=0;
};
然后将函数的参数声明为指向duck的指针。你的类必须继承这个类,使let_them_quack()
的要求变得清晰。
就#1而言,可变参数模板可以解决这个问题。
void let_them_quack()
{
}
template <typename ...Args>
void let_them_quack(duck* first_duck, Args && ...args) {
first_duck->quack();
let_them_quack(std::forward<Args>(args)...);
}
答案 3 :(得分:1)
你将能够使它看起来更具概念性(尚未达到标准 - 但非常接近):
http://melpon.org/wandbox/permlink/Vjy2U6BPbsTuSK3u
#include <iostream>
template<typename T>concept bool ItQuacks(){
return requires (T a) {
{ a.quack() } -> void;
};
}
void let_them_quack2(ItQuacks* donald, ItQuacks* daisy){
donald->quack();
daisy->quack();
}
struct DisneyDuck {
void quack(){ std::cout << "Quack!";}
};
struct RegularDuck {
void quack(){ std::cout << "Quack2!";}
};
struct Wolf {
void woof(){ std::cout << "Woof!";}
};
int main() {
DisneyDuck q1, q2;
let_them_quack2(&q1, &q2);
RegularDuck q3, q4;
let_them_quack2(&q3, &q4);
//Wolf w1, w2;
//let_them_quack2(&w1, &w2); // ERROR: constraints not satisfied
}
输出:
Quack!Quack!Quack2!Quack2!
正如您所看到的,您将能够:omit writing a template parameter list
,ItQuacks非常明确,因此发生了types are never used and that it's only the interface that matters
。此I'd like to have sort of an interface annotation/check.
也会发生,概念使用也会为您提供有意义的错误消息。
答案 4 :(得分:0)
我们只需编写一个版本的函数:
#include <utility>
template<typename... Quackers>
void let_them_quack(Quackers&& ...quackers) {
using expand = int[];
void(expand { 0, (std::forward<Quackers>(quackers).quack(), 0)... });
}
struct Duck {
void quack() {}
};
int main()
{
Duck a, b, c;
let_them_quack(a, b, c, Duck());
}