how to use a base class template function in a derived case?
Example:
Class A{
protected:
template<typename... Args>
std::vector<torch::Tensor> generate_value(const size_t& generated_points, std::function<int(const Args&...)> function, const Args&... args);
};
class B : protected A{
public:
B() : A(){}
protected:
std::vector<torch::Tensor> generate_values(const size_t& generated_points, const size_t& column){
return this->generate_values(generated_points, std::bind(&A::inner_generation, this, std::placeholders::_1), column);
}
<torch::Tensor inner_generation(const size_t& column);
};
Compiling use Clang I get the following error:
error: no matching member function for call to 'generate_values'
return this->generate_values(generated_points, function, column);
~~~~~~^~~~~~~~~~~~~~~
note: candidate template ignored: could not match 'std::function<torch::Tensor (const Args &...)>
std::vector<torch::Tensor> generate_values(const size_t& generated_points, std::function<torch::Tensor(const Args&...)> function, const Args&... args)
I am not sure what is the issue.
I hope someone could guide me.
Originally, I had the function with same name, it was only finding the one in class B
. I have then changed the names it is still not found. I am not sure is that due to the template
.
std::function
is rather expensive in usage and little flexible – if you go along with yet another template parameter you are more efficient, more flexible and even get simpler code:
class A
{
protected:
template<typename F, typename... Args>
std::vector<torch::Tensor> generate_value
(
size_t generated_points, // no benefit from reference...
F&& f // the function/functor to execute
Args&&... args // allows perfect forwarding
)
{
f(std::forward<Args>(args)...);
}
};
std::vector<torch::Tensor> B::generate_values(size_t generated_points, size_t column)
{
return generate_values
(
generated_points,
// simply use a lambda, it's just more convenient:
[this](size_t column) { return inner_generation(column); },
// though the result of `bind` would be just as valid...
column // and the parameter...
);
}
Though if using lambdas (or std::bind
as well, if you bind the values directly instead of using place holders) you don't even need additional parameters:
template<typename F>
std::vector<torch::Tensor> A::generate_value(size_t generated_points, F&& f)
{
f();
}
std::vector<torch::Tensor> B::generate_values(size_t generated_points, size_t column)
{
return generate_values
(
generated_points,
[this, column] { return inner_generation(column); }
// alternatively with default bindings:
//[=] { return inner_generation(column); }
);
}
Which one to choose? Well, a matter of personal taste mainly – unless you want to do the same multiple times with different variables, then the former variant is of advantage for not having to create multiple lambdas:
std::vector<torch::Tensor> B::generate_values
(
size_t generated_points,
size_t column1,
size_t column2 // now one more...
)
{
auto gen = [this](size_t column) { return inner_generation(column); };
auto v1 = generate_values(generated_points, gen, column1);
auto v2 = generate_values(generated_points, gen, column2);
// union both, create difference or do whatever is appropriate...
return ...;
}
This latter example might not be meaningful in your concrete case, but might come into play in other scenarios ;)
Side note: Just for explanation: The original variant fails for neither the result of bind
nor a lambda actually being a std::function
object, thus not matching your template parameter. You can solve by creating the std::function
object explicitly:
return A::generate_values
(
generated_points,
std::function([this](size_t const& column) { return inner_generation(column); }),
// alternatively with `bind`ing, though the place holder makes
// explicitly specifying the template argument necessary:
//std::function<torch::Tensor(size_t const&)>
//(
// std::bind(&B::inner_generation, this, std::placeholders::_1)
//),
column
);
Note, too, that in the original code of the question the return types of the std::function
instantiations do not match either (first int
, then torch::Tensor
– unless torch::Tensor
happens to be a typedef
for int
…).