编译时构造函数选择

时间:2018-03-21 08:23:29

标签: c++ templates variadic-templates c++17 template-meta-programming

我正在尝试实施以下API:

geojson::position_t<> point_1{ 10, 12 };
geojson::position_t<> point_2( 11, 13 );
geojson::position_t<> point_3(std::pair<int, int>(12, 14));

geojson::position_t<> line_1{ 
   geojson::position_t<>{ 100, 120 }, 
   geojson::position_t<>{ 110, 130 } };

geojson::position_t<> poly_1{
  { geojson::position_t<>{ 100, 120 }, geojson::position_t<>{ 110, 130 }}, 
  { geojson::position_t<>{ 101, 121 }, geojson::position_t<>{ 111, 131 }} };

我们的想法是拥有 position_t&lt;&gt; 模板类,其中包含以下属性:

  • 有一些内部value_type来识别它是点还是 行
  • 有构造函数并使用SFINAE来识别是否为点类型或 可以根据传递给ctor
  • 的参数创建line-type
  • 让方法value_type get() const {...}返回点或线类型 取决于是否调用了点或线ctor

我的第一种方法是使用boost :: variant,但我不知道如何获得value_type并实现get()方法。

第二次尝试是使用部分模板专业化。但到目前为止,我没有成功。wandbox example

有人可以建议如何实现所需的API吗?

2 个答案:

答案 0 :(得分:2)

在C ++ 17中,您可以使用推导出的指南,因此您同时拥有position_t<Point>position_t<Line>,并根据参数构造函数选择正确的指南。

类似的东西:

class Point
{
public:
    int x;
    int y;
};

class Line
{
public:
    Point start;
    Point end;
};

template <typename T> class position_t;

template <>
class position_t<Point>
{
public:
    position_t(int x, int y) : point{x, y} {}
    position_t(const std::pair<int, int>& p) : point{p.first, p.second} {}

    const Point& get() const { return point; }
private:
    Point point;  
};

template <>
class position_t<Line>
{
public:
    position_t(const position_t<Point>& start,
               const position_t<Point>& end)
        : line{start.get(), end.get()}
    {}

    const Line& get() const { return line; }
private:
    Line line;  
};

然后是演绎指南

position_t(int, int) -> position_t<Point>;
position_t(std::pair<int, int>) -> position_t<Point>;
position_t(const position_t<Point>&, const position_t<Point>&) -> position_t<Line>;

所以:

geojson::position_t point_1{ 10, 12 }; // geojson::position_t<Point>
geojson::position_t point_2( 11, 13 ); // geojson::position_t<Point>
geojson::position_t point_3(std::pair<int, int>(12, 14)); // geojson::position_t<Point>

geojson::position_t line_1{ // geojson::position_t<Line>
    geojson::position_t{ 100, 120 },   // geojson::position_t<Point>
    geojson::position_t{ 110, 130 } }; // geojson::position_t<Point>

Demo

答案 1 :(得分:1)

以下是两个可选解决方案:

第一个使用标准多态,它使用基类fun showHide(view:View) { view.visibility = if (view.visibility == View.VISIBLE){ View.INVISIBLE } else{ View.VISIBLE } } 。 第二种方法是使用std :: variant来保存对象。如果使用它,则可以删除基类和虚函数。从评论中读取,您会看到类型扣除规则作为解决方案。是的,我的例子那样工作!

它对于vtable多态性与标记的union作为std :: variant有一些利弊。两者都有可能!

评论:

  

有一些内部value_type标识它是点还是行

您不需要一些额外的标识符,因为变体本身已包含该类型标记。变量只是一个联合和一个附加数据条目,它跟踪实际分配的类型。正是你想要的!您可以使用GraphicBase这些标记来调用传递给您传递的函数对象的相应类型的任何函数。 (在我的例子中,我使用通用lambda使调度变得非常容易。

提示: 如果可以进行简单的过载或专业化,请不要考虑SFINAE!

std::visit