问题
So I've written an answer which uses a templatized function to select object type.
I've defined the types:
struct pt {
double t;
double e;
double c_vis;
double c_invis;
};
struct pt_weighted : pt {
double sigma;
};
And my templatized function looks like:
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;
}
}
Given that minimizator_weighted
decides which type to use at runtime, I call foo
with:
minimizator_weighted ? foo<data_set::pt_weighted>() : foo<data_set::pt>();
Richard Hodges is suggesting using Argument Dependent Lookup (ADL) to avoid "explicitly specialized template functions". I'm just not sure what he means so I thought I'd open a new question so he or someone could explain further in an answer.
回答1:
something along these lines.
Note that I can now add a new point type (or set type) without changing the logic in more than one function. All I have to do is provide ADL overloads of operator>>
and do_something
for the new types.
So my core logic is now separated from the implementation details of each set type/point type. If I want to use the same code points in some other co-ordinate system I have less code to change (in a real project).
#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());
}
};
回答2:
In the example below you don't need to specify the type of points that you'll be reading in. Instead, the compiler can figure that out by the argument you've passed into the function. (NOTE: This code block assumes that set
, dataFile
, and data_numPoints
are accessible and mutable from within the function.)
template<class T>
void foo(T point) {
while (dataFile >> point) {
set.curve.push_back(point);
data_numPoints++;
set.curveAvg += point.e;
}
}
Now, to call it, you just pass in an instance of the type you care about.
void bar() {
foo(data_set::pt()); // builds unweighted data set
foo(data_set::pt_weighted()); // builds weighted data set
}
回答3:
If you want template argument deduction, you have to deduce it from something. For example, you can deduce a function template parameters from it's arguments. For example, you can change your function to this:
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;
}
}
Then when you call your function, you can deduce it like this:
data_set::pt_weighted ptw;
data_set::pt pt;
minimizator_weighted ? foo(ptw) : foo(pt);
来源:https://stackoverflow.com/questions/41128744/how-can-i-avoid-explicitly-specializing-templatized-functions-with-argument-depe