编译器如何使用策略模式(在结构中使用 overloaded() 或 class)推断类型?
How the compiler infer types using strategy pattern (with overloaded() in struct or class)?
我很难理解在传递“可调用”时,这段代码是如何编译的struct/class。
参考下面的 main
函数,我希望编译器告诉我 Point3D 没有匹配的构造函数(CallableI
不是FuncType
).
的实例
我很想做的是在 CallableI
中创建一个 algo
成员并构建引用它的点。但是这个解决方案在很多方面都更好,所以我想了解它是如何工作的。
我有一个基地class Point3D :
template<typename T>
class Point3D
{
typedef std::function<T (const Point3D<T> &p1, const Point3D<T> &p2)> FuncType;
private:
T x;
T y;
T z;
FuncType algo;
public:
Point3D(T x, T y, T z, FuncType algo) : x(x), y(y), z(z), algo(algo){}
T First() const {return x;}
T Second() const {return y;}
T Third() const {return z;}
T computeDistance(Point3D<T> &p2){
return algo(*this, p2);
}
};
我正在使用一个结构 CallableI
来保存一个特定的函数来调用重载运算符 ()
。
struct CallableI
{
CallableI(){};
double operator() (const Point3D<double> &p1, const Point3D<double> &p2){
double x1{p1.First()}; double x2{p2.First()};
double y1{p1.Second()}; double y2{p2.Second()};
return std::abs(x1 - x2) + std::abs(y1 - y2);
}
};
我正在使用下面的主要函数调用建议的代码:
int main(int argc, char **argv) {
CallableI myCallable;
Point3D<double> p1(14.3, 12.3, 2.0, myCallable);
return 0;
std::function
是类型擦除模板。
std::function<R(Arg0, Arg1)>
是类型擦除类型。
它可以用你能用的任何值构造:
- 用
()
和Arg0, Arg1
调用,return类型可以转换为R
- 可以复制、移动和销毁。
是一种不需要继承的多态
您的 CallballI
满足要求,function<double(Point3D<double> const&,Point3D<double> const&)>
的构造函数完成工作以使其工作。
C++ 中的类型擦除是如何工作的是一个更高级的主题。在 std::function
中,它是如何工作的是未指定的;该标准只是说它有效。您可以通过多种方式自己实现它(反过来可以使用继承),但在您学习 C++ 的这一点上,我建议您不要这样做。
核心思想是 C++ 模板非常强大,std::function
有一个模板构造函数,可以编写胶水代码,让您存储未知但兼容类型的对象,并编写代码来调用 (Point3D<double>, Point3D<double>)
就可以了。
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
void* pstate = nullptr;
R(*pf)(void*, Args&&...) = nullptr;
R operator()(Args... args) const {
return pf(pstate, std::forward<Args>(args)...);
}
template<class T>
function_view( T&& in ):
pstate( (void*)std::addressof(in) ),
pf( [](void* pvoid, Args&&...args )->R {
return (*decltype(std::addressof(in))(pvoid))( std::forward<Args>(args)... );
})
{}
};
这是一个半有用的非拥有功能视图的不完整(以多种方式简化)草图。这不是在 C++ 中进行类型擦除的唯一方法,只是一种残酷、简单和简短的方法。
核心是 function_view<Sig>
知道它需要什么,它在构建时保存了如何做,然后忘记了关于传递的类型的所有其他内容(它从内存中“擦除”它)。
然后,当您要求它执行操作时,它会使用这些已保存的操作对类型擦除的数据进行操作。
这里,
void foo( function_view<int(int)> f ) {
std::cout << f(3);
}
foo
不是模板,但可以接受任何支持调用 int
和 return 的不相关类型,可以转换为 int
。
我很难理解在传递“可调用”时,这段代码是如何编译的struct/class。
参考下面的 main
函数,我希望编译器告诉我 Point3D 没有匹配的构造函数(CallableI
不是FuncType
).
我很想做的是在 CallableI
中创建一个 algo
成员并构建引用它的点。但是这个解决方案在很多方面都更好,所以我想了解它是如何工作的。
我有一个基地class Point3D :
template<typename T>
class Point3D
{
typedef std::function<T (const Point3D<T> &p1, const Point3D<T> &p2)> FuncType;
private:
T x;
T y;
T z;
FuncType algo;
public:
Point3D(T x, T y, T z, FuncType algo) : x(x), y(y), z(z), algo(algo){}
T First() const {return x;}
T Second() const {return y;}
T Third() const {return z;}
T computeDistance(Point3D<T> &p2){
return algo(*this, p2);
}
};
我正在使用一个结构 CallableI
来保存一个特定的函数来调用重载运算符 ()
。
struct CallableI
{
CallableI(){};
double operator() (const Point3D<double> &p1, const Point3D<double> &p2){
double x1{p1.First()}; double x2{p2.First()};
double y1{p1.Second()}; double y2{p2.Second()};
return std::abs(x1 - x2) + std::abs(y1 - y2);
}
};
我正在使用下面的主要函数调用建议的代码:
int main(int argc, char **argv) {
CallableI myCallable;
Point3D<double> p1(14.3, 12.3, 2.0, myCallable);
return 0;
std::function
是类型擦除模板。
std::function<R(Arg0, Arg1)>
是类型擦除类型。
它可以用你能用的任何值构造:
- 用
()
和Arg0, Arg1
调用,return类型可以转换为R
- 可以复制、移动和销毁。
是一种不需要继承的多态
您的 CallballI
满足要求,function<double(Point3D<double> const&,Point3D<double> const&)>
的构造函数完成工作以使其工作。
C++ 中的类型擦除是如何工作的是一个更高级的主题。在 std::function
中,它是如何工作的是未指定的;该标准只是说它有效。您可以通过多种方式自己实现它(反过来可以使用继承),但在您学习 C++ 的这一点上,我建议您不要这样做。
核心思想是 C++ 模板非常强大,std::function
有一个模板构造函数,可以编写胶水代码,让您存储未知但兼容类型的对象,并编写代码来调用 (Point3D<double>, Point3D<double>)
就可以了。
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
void* pstate = nullptr;
R(*pf)(void*, Args&&...) = nullptr;
R operator()(Args... args) const {
return pf(pstate, std::forward<Args>(args)...);
}
template<class T>
function_view( T&& in ):
pstate( (void*)std::addressof(in) ),
pf( [](void* pvoid, Args&&...args )->R {
return (*decltype(std::addressof(in))(pvoid))( std::forward<Args>(args)... );
})
{}
};
这是一个半有用的非拥有功能视图的不完整(以多种方式简化)草图。这不是在 C++ 中进行类型擦除的唯一方法,只是一种残酷、简单和简短的方法。
核心是 function_view<Sig>
知道它需要什么,它在构建时保存了如何做,然后忘记了关于传递的类型的所有其他内容(它从内存中“擦除”它)。
然后,当您要求它执行操作时,它会使用这些已保存的操作对类型擦除的数据进行操作。
这里,
void foo( function_view<int(int)> f ) {
std::cout << f(3);
}
foo
不是模板,但可以接受任何支持调用 int
和 return 的不相关类型,可以转换为 int
。