【发布时间】:2018-08-23 20:07:31
【问题描述】:
设置
考虑两种类型,其中一种继承自另一种:
#include <iostream>
class shape { };
class circle : Shape { };
还有两个函数分别接受该类型的对象:
void shape_func(const shape& s) { std::cout << "shape_func called!\n"; }
void circle_func(const circle& c) { std::cout << "circle_func called!\n"; }
函数模板
现在我想要一个函数模板,我可以传递给它:
- 其中一种类型的对象(或其他类似类型)。
- 指向与传递的对象兼容的那些函数之一的指针(或其他类似的)。
以下是我声明这个函数模板的尝试:
template<class T>
void call_twice(const T& obj, void(*func)(const T&))
{
func(obj);
func(obj);
}
(实际上它的主体会做一些更有用的事情,但为了演示目的,我只是让它用传递的对象调用传递的函数两次。)
观察到的行为
int main() {
shape s;
circle c;
call_twice<shape>(s, &shape_func); // works fine
call_twice<circle>(c, &circle_func); // works fine
//call_twice<circle>(c, &shape_func); // compiler error if uncommented
}
预期行为
我希望第三次调用也能奏效。
毕竟,由于shape_func 接受任何shape,它也接受circle — 所以通过用circle 代替T,编译器应该可以解析函数模板而不会发生冲突。
事实上,这就是对应的泛型函数在 C# 中的行为方式:
// C# code
static void call_twice<T>(T obj, Action<T> func) { ... }
它可以毫无问题地称为call_twice(c, shape_func),因为用C#术语来说,Action<T>的类型参数T是contravariant。
问题
这在 C++ 中可行吗?
也就是说,必须如何实现函数模板call_twice 才能接受本示例中的所有三个调用?
【问题讨论】:
-
不确定我是否关注,你的意思是something like this?
-
@WhozCraig:是的,这就是我想要的行为!谢谢!你能把它作为答案发布并解释一下吗?
标签: c++ contravariance