如何避免使用参数依赖查找显式专门化模板化函数

时间:2016-12-13 19:07:26

标签: c++ runtime specialization argument-dependent-lookup function-templates

所以I've written an answer使用模板化函数来选择对象类型。

我已经定义了类型:

struct pt {
    double t;
    double e;
    double c_vis;
    double c_invis;
};

struct pt_weighted : pt {
    double sigma;
};

我的模板化功能看起来像:

template <typename T>
void foo() {
    for(T point; dataFile >> point;) {
        set.curve.push_back(point); // store point

        data_numPoints++; // collect some stats
        set.curveAvg += point.e;            
    }
}

鉴于minimizator_weighted决定在运行时使用哪种类型,我将foo称为:

minimizator_weighted ? foo<data_set::pt_weighted>() : foo<data_set::pt>();

Richard Hodges is suggesting使用Argument Dependent Lookup (ADL)来避免“明确专门的模板功能”。我只是不确定他的意思,所以我想我会打开一个新问题,这样他或某人就可以在答案中进一步解释。

3 个答案:

答案 0 :(得分:3)

沿着这些方向发展。

请注意,我现在可以添加新的点类型(或集类型),而无需更改多个函数中的逻辑。我所要做的就是为新类型提供operator>>do_something的ADL重载。

因此,我的核心逻辑现在与每个集类型/点类型的实现细节分开。如果我想在其他一些坐标系统中使用相同的代码点,我需要更少的代码(在实际项目中)。

#include <iostream>
#include <vector>

struct pt {
    double t;
    double e;
    double c_vis;
    double c_invis;
};
std::istream& operator>>(std::istream& is, pt& p)
{
  p.c_vis = 0;
  p.c_invis = 0;
  return is >> p.t >> p.e;
}

struct pt_weighted : pt {
    double sigma;
};

std::istream& operator>>(std::istream& is, pt_weighted& p)
{
    auto sigma_correction = [](double& sigma) {
      // whatever this is supposed to do;
    };
  is >> static_cast<pt&>(p) >> p.sigma;
  sigma_correction(p.e);
  return is;
}


template<class Point> struct set
{
  using point_type = Point;   // the type name point_type is now part of the set's type interface, so I can use it in dependent code.
  std::vector<point_type> points;
};

using pt_set = set<pt>;
using pt_weighted_set = set<pt_weighted>;


//
// one implementation of read logic, for all set types.
//
template<class SetType>
void read_set(std::istream& is, SetType& target)
{
  while(is) {
    // using the type protocol here
    auto point = typename SetType::point_type(); // or target.makePoint() ?
    is >> point;
    target.points.push_back(std::move(point));    
  }
}

extern void do_something(pt_set&);
extern void do_something(pt_weighted_set&);

void operation(std::istream& is)
{
  extern bool useSigma();

  // even these lines now no longer need to be repeated
  auto perform = [](auto&& myset) {
    read_set(is, myset);
    do_something(myset);
  };

  if (useSigma())
  {
    perform(pt_weighted_set());
  }
//else if (someOtherCondition()) {
//  perform(someOtherSetType());
//}
  else {
    perform(pt_set());
  }
};

答案 1 :(得分:1)

在下面的示例中,您不需要指定要读取的点的类型。相反,编译器可以通过您传递给函数的参数来计算出来。 (注意:此代码块假定setdataFiledata_numPoints可以从函数中访问和更改。)

template<class T>
void foo(T point) {
    while (dataFile >> point) {
        set.curve.push_back(point);
        data_numPoints++;
        set.curveAvg += point.e;
    }
}

现在,要调用它,您只需传入您关心的类型的实例。

void bar() {
    foo(data_set::pt()); // builds unweighted data set
    foo(data_set::pt_weighted()); // builds weighted data set
}

答案 2 :(得分:0)

如果你想要模板参数推导,你必须从某些东西中推断它。例如,您可以从其参数中推导出函数模板参数。例如,您可以将功能更改为:

template <typename T>
void foo(T p) {
    for(T point = p; dataFile >> point;) {
        set.curve.push_back(point); // store point

        data_numPoints++; // collect some stats
        set.curveAvg += point.e;            
    }
}

然后当你调用你的函数时,你可以这样推断它:

data_set::pt_weighted ptw;
data_set::pt pt;

minimizator_weighted ? foo(ptw) : foo(pt);