Setting a std::function variable to refer to the std::sin function - c++

I've got a question about how to properly use the new C++11 std::function variable. I've seen several examples from searching the Internet, but they don't seem to cover the usage case I'm considering. Take this minimum example, where the function fdiff is an implementation of the finite forward differencing algorithm defined in numerical.hxx (which isn't the problem, I just wanted to give a contextual reason why I'd want to take an arbitrary function and pass it around).
#include <functional>
#include <iostream>
#include <cmath>
#include "numerical.hxx"
int main()
{
double start = 0.785398163;
double step = 0.1;
int order = 2;
std::function<double(double)> f_sin = std::sin;
std::cout << fdiff(start, step, order, f_sin) << std::endl;
return 0;
}
Attempting to compile the above program gives me the error (in clang++)
test.cpp:11:32: error: no viable conversion from '<overloaded function type>' to
'std::function<double (double)>'
std::function<double(double)> f_sin = std::sin;
^ ~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2048:7: note:
candidate constructor not viable: no overload of 'sin' matching
'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2059:7: note:
candidate constructor not viable: no overload of 'sin' matching 'const
std::function<double (double)> &' for 1st argument
function(const function& __x);
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2068:7: note:
candidate constructor not viable: no overload of 'sin' matching
'std::function<double (double)> &&' for 1st argument
function(function&& __x) : _Function_base()
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2092:2: note:
candidate template ignored: couldn't infer template argument '_Functor'
function(_Functor __f,
^
1 error generated.
or from g++
test.cpp: In function ‘int main()’:
test.cpp:11:45: error: conversion from ‘<unresolved overloaded function type>’ to non-scalar type ‘std::function<double(double)>’ requested
As I understand the problem, it's because std::sin is implemented as a template class in the standard library, but I can't seem to figure out what I need to do to give enough of a specialization to get a function reference. I've also tried various things like using the new auto keyword, using &std::sin to get a pointer, etc., but they all give me the same type of error.

std::sin is an overloaded function: you must disambiguate which std::sin overload you mean:
std::function<double(double)> f_sin = (double(*)(double))&std::sin;
There are some cases where the compiler can disambiguate overloaded functions (e.g., if f_sin was of type double(*)(double), the cast would not be required). However, this is not one of those cases.

With lambda you will be always on safe side:
std::function<double(double)> f_sin = [](double arg) -> double { return std::sin(arg); };
Actually you can do better, if you can change fdiff or it is already accepting template parameter - not just std::function<double(double)>:
auto f_sin = [](double arg) -> double { return std::sin(arg); };
std::cout << fdiff(start, step, order, f_sin) << std::endl;
[UPDATE] This answer is new version, previous advice to use function template specialization was incorrect, since std::sin is not function template but set of overloaded functions.

Related

Error "lambda is not derived from 'std::function'

I'm trying to pass lambda to std::function<> defined via variadic template, but it seems that this doesn't work on gcc.
Is there any reason, why this code doesn't work on gcc 7.4.0 but working correctly on Visual Studio 2017? And is there any way how to make it work also on gcc without the necessity to manually convert it to std::function<> first?
#include <functional>
template<class ...TParams>
int TestFunction(std::function<void(TParams...)> )
{
return 0;
}
void Test()
{
auto fce = [](int /*n*/, double /*d*/) {};
//This doesn't work with error no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
//but this works correctly
std::function<void(int, double)> fce2 = fce;
TestFunction<int, double>(fce2);
}
I'm getting following error:
main.cpp: In function 'void Test()':
main.cpp:116:31: error: no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
^
main.cpp:106:5: note: candidate: template<class ... TParams> int TestFunction(std::function<void(TParams ...)>)
int TestFunction(std::function<void(TParams...)> fceCallback)
^~~~~~~~~~~~
main.cpp:106:5: note: template argument deduction/substitution failed:
main.cpp:116:31: note: 'Test()::<lambda(int, double)>' is not derived from 'std::function<void(TParams ...)>'
TestFunction<int, double>(fce);
^
A trailing template parameter pack always leaves room for further deduction. Specifying the first two arguments doesn't prevent you from doing something like this:
std::function<void(int, double, char)> fce3 ;
TestFunction<int, double>(fce3);
In this case, the pack will contain int, double, char, because the char was deduced from the function argument. Now, because deduction isn't over, and a lambda is not a std::function, the substitution fails.
To make this work, you need to let the deduction process know it's over, that an instantiated function is needed now, before it's given an argument. One way to do that is to take the function's address, for instance:
auto pfunc = TestFunction<int, double>;
pfunc(fce);
or
(&TestFunction<int, double>)(fce);
Taking a function template's address is another context where template argument deduction can occur. In this case, the trailing pack is deduced as empty, and you get a pointer to a function you may call.

In C++, when no constructor is declared for a class, what will happen if I construct an object with arguments?

I have the struct student and I did not declare a constructor. What will happen if I do the following?
struct student{
int assns, mt, finalExam;
float grade(){…}
}
student billy (60, 70, 80);
This answer is written according to the question heading, and not the body, as they seem to be gravely conflicting, hope the OP edits this.
You will encounter a error during compile time.
Code:
#include <iostream>
class test
{
int tt;
};
int main ()
{
test t1 (34);
}
Compiler Error:
In function 'int main()':
10:17: error: no matching function for call to 'test::test(int)' 10:17: note: candidates are:
2:7: note: test::test()
2:7: note: candidate expects 0 arguments, 1 provided
2:7: note: constexpr test::test(const test&)
2:7: note: no known conversion for argument 1 from 'int' to 'const test&'
2:7: note: constexpr test::test(test&&)
2:7: note: no known conversion for argument 1 from 'int' to 'test&&'
This happens as there is no constructor defined which takes a parameter. Without the ctor there is no meaning of class, as you can never initialize its data member, and how can you expect something to be constructed if the construction company itself is absent.
The compiler will throw error.

Member function pointer issue with standard library methods

This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.

Passing a member function pointer to an overloaded class method into a template function [duplicate]

This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.

Adding to a Protocol Buffers repeated field

I'm working in C++ with a Protocol Buffer template including the following message:
message StringTable {
repeated bytes s = 1;
}
I'm attempting to add a new value to the existing data, like so:
pb.stringtable().s().Add(replace_key);
However, this generates an error on compilation (using clang on OS X):
test.cpp:51:4: error: member function 'Add' not viable: 'this' argument
has type 'const ::google::protobuf::RepeatedPtrField< ::std::string>',
but function is not marked const
pb.stringtable().s().Add(replace_key);
^~~~~~~~~~~~~~~~~~~~
Any clues? I'm very much a C++ newbie so may be making a dumb error.
Edit:
Using the accessors produces a similar error:
pb.stringtable().add_s(replace_key);
results in:
test.cpp:51:21: error: no matching member function for call to 'add_s'
pb.stringtable().add_s(replace_key);
~~~~~~~~~~~~~~~~~^~~~~
./osmformat.pb.h:3046:26: note: candidate function not viable: 'this' argument has type 'const ::StringTable', but method is not marked const
inline void StringTable::add_s(const ::std::string& value) {
^
./osmformat.pb.h:3050:26: note: candidate function not viable: 'this' argument has type 'const ::StringTable', but method is not marked const
inline void StringTable::add_s(const char* value) {
^
./osmformat.pb.h:3043:36: note: candidate function not viable: requires 0 arguments, but 1 was provided
inline ::std::string* StringTable::add_s() {
^
./osmformat.pb.h:3054:26: note: candidate function not viable: requires 2 arguments, but 1 was provided
inline void StringTable::add_s(const void* value, size_t size) {
Problem solved.
The existing StringTable isn't mutable by default. However, using the mutable_ accessors makes it so:
pb.mutable_stringtable().add_s(replace_key);