I try to use boost::bind with std::vector<>::resize.
But the following code won't compile:
#include <boost/bind.hpp>
#include <vector>
using namespace boost;
int main(){
typedef std::vector<double> type;
type a;
bind(&type::resize, _1, 2)(a);
return 0;
}
So, how can I do this?
Thanks!
boost version 1.53
gcc version 4.8 or 4.6
*Edit: * The above code works with -std=c++11. In fact, my original problem is this:
#include <boost/bind.hpp>
#include <blitz/array.h>
#include <vector>
using namespace boost;
using namespace blitz;
int main(){
typedef Array<double, 1> type;
type a;
//a.resize(4) is ok;
bind(&type::resize, _1, 2)(a);
return 0;
}
My compile command is:
g++ t.cpp -I path/include/ -std=c++11 -L path/lib/ -l blitz
resize might be an overloaded function (in C++11 it has to be) so you need to tell the compiler which overload you want. For the one argument form, this should work in C++11:
bind(static_cast<void (type::*)(type::size_type)>(&type::resize), _1, 2)(a);
Or more readably:
typedef void (type::*resize_signature)(type::size_type);
bind(static_cast<resize_signature>(&type::resize), _1, 2)(a);
If it's not an overloaded function (as with GCC in C++03 mode) then it takes two arguments (one has a default value) and you need to supply the second argument because bind can't use default arguments:
typedef void (type::*resize_signature)(type::size_type, const value_type&);
bind(static_cast<resize_signature>(&type::resize), _1, 2, 0.0)(a);
Unfortunately this C++03 version isn't portable, implementations are allowed to use a single function or a pair of overloads. To make it portable, or to work with other types such as Array you can wrap the call in a custom functor that calls resize, so you don't need to know the exact signature:
typename<class VecT>
struct resizer<VecT> {
void operator()(VecT& v, unsigned n) const { v.resize(n); }
};
// ...
bind(resizer<type>(), _1, 2)(a);
Or in C++11 just use a lambda expression instead of bind:
auto resize = [](type& v) { v.resize(2); };
resize(a);
Related
This question already has an answer here:
Can class template constructors have a redundant template parameter list in c++20
(1 answer)
Closed 1 year ago.
Specifically it is (an excerpt from https://github.com/dillonhuff/gpr), which fails to compile on line with parse_stream constructor definition:
#include "parser.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <streambuf>
using namespace std;
namespace gpr {
template<typename T>
struct parse_stream {
size_t i;
vector<T> s;
template<typename R>
parse_stream<T>(R v) : s(v.begin(), v.end()) { // COMPILE ERROR: expected ')' before 'v'
i = 0;
}
(...)
}
and parser.h just contains this:
#pragma once
#include <string>
#include "gcode_program.h"
namespace gpr {
std::vector<std::string> lex_block(const std::string& block_text);
gcode_program parse_gcode(const std::string& program_text);
gcode_program parse_gcode_saving_block_text(const std::string& program_text);
}
This used to compile just fine with MSVC 2019, and just "a while ago" with lower MinGW-64 gcc version. It seems to have something to do with C++ standard (17 vs 20), as lowering the C++ version settings in the Qt .pro file seems to fix it (but then I loose .contains() from std::map and couple of other features).
Maybe I am blind, but I just don't see, what is wrong here! Please help.
EDIT: Adding an exact compiler error
../gpr/src/parser.cpp:19:22: error: expected ')' before 'v'
19 | parse_stream<T>(R v) : s(v.begin(), v.end()) {
| ~ ^~
| )
EDIT: NathanOliver's comment helps to resolve the compilation. It compiles with (without the T parameter declaration):
template<typename R>
parse_stream(R v) : s(v.begin(), v.end()) { // NOW OK!
i = 0;
}
(Not sure if it is a fix or a workaround to a compiler bug, as the main question remains unanswered.)
Why is there no initializer for i in the list initializer?
It should read like this:
template <class R> explicit parse_stream(R v) : i{}, v{ std::vector<T>(v.begin(), v.end()) } {}
EDIT: It might make sense to provide an overload for the case where R is of decltype (v), namely a std::vector<T>, in which case we could just move the whole thing. Like this:
explicit parse_stream(std::vector<T> v) : i{}, v{ std::move(v) } {}
I have the following simplified code where the compiler is not recognizing the data types and I am not sure why. In the code, I want to be able to pass a map, where the keywords can either be a std::string, a char, or an int. I also want the user to be able to choose whether the associated value is a float or double. In addition, based on the type of the associated value I want the return to either be std::vector<float> or std::vector<double>. Due to the variability in data types, I choose to code this problem as a template.
// main.cpp
#include "test.hpp"
#include <iostream>
#include <math.h>
#include <map>
#include <tuple>
double func6(std::map<char, double> arr);
int main(int argc, const char * argv[]) {
std::map<char, double> inputs;
inputs['x'] = 2.0;
inputs['y'] = 5.438;
std::tuple<std::vector<double>, std::vector<double>> answer;
ODESolver q;
answer = q.ode_solver(inputs, func6);
// - The line below this was tried and it did not work
// any better than the line of code above this.
// answer = q.ode_solver<char, double>(inputs, func6);
return 0;
}
double func6(std::map<char, double> arr)
{
return arr['y'] * log(arr['y']) / arr['x'];
}
The .hpp file has the following information.
#ifndef test_hpp
#define test_hpp
#include <stdio.h>
#include <tuple>
#include <vector>
#include <map>
#include <functional>
class ODESolver
{
public:
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<real_type(std::map<char_type, real_type>)>& func)
{
// - This function does not work with the function call
// as written
// - The code in this function is irrelevant, it was just
// created to have returnable information of the correct
// type to test the function call
std::vector<real_type> one = {0.0, 1.0};
std::vector<real_type> two = {0.0, 1.0};
std::tuple<std::vector<real_type>, std::vector<real_type>> three(one, two);
return three;
}
};
#endif /* test_hpp */
The compiler does not allow the template shown above, because it does not recognize a matching function call for answer= q.ode_solver(inputs, func6) in the main program. However, if I replace the std::function statement with the following code it works fine.
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<double(std::map<char, double>)>& func)
All I am doing is replacing the templated parameters with the parameters I want to use in this exact situation, but that defeats the reason for using a template. I have also tried calling the function with answer = q.ode_solver<char, double>(inputs, func6); and it still does not recognize the function. What am I missing?
Implicit conversions (from the function pointer to std::function in this case) won't be considered in template argument deduction.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can add an explicit conversion, e.g.
answer = q.ode_solver(inputs, static_cast<std::function<double(std::map<char, double>)>>(func6));
or specify the template arguments explicitly (I'm not sure why you said it didn't work, see the live demo linked below)
answer = q.ode_solver<char, double>(inputs, func6);
LIVE
Or just add another template parameter instead of using std::function.
template<class char_type, class real_type, class F>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const F& func)
boost::iostreams::tee and company have a bit of a noisy/repetitive usage as seen here:
C++ "hello world" Boost tee example program
The goal is to make something like:
auto myTeeStream = make_tee(std::cout, myfile);
After trying to wrap this usage with a function make_tee to allow for automatic type deduction on the arguments I realized that both copy and move constructors are unavailable for the necessary types.
So: is there a sane way to wrap tee stream creation in c++11?
Here's my attempt that fails to compile because of deleted copy constructors and missing move constructors:
#include <iostream>
#include <ostream>
#include <fstream>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
template <typename StreamT1, typename StreamT2>
boost::iostreams::stream<boost::iostreams::tee_device<StreamT1, StreamT2> >
make_tee(StreamT1 & t1, StreamT2 & t2)
{
using boost::iostreams::stream;
using boost::iostreams::tee;
return stream<decltype(tee(t1,t2))>(tee(t1,t2)); // compile error
//return std::move(stream<decltype(tee(t1,t2))>(tee(t1,t2))); // also fails of course
}
int main()
{
{
// desired usage
std::ofstream myFile("file.txt");
auto && myTee = make_tee(std::cout, myFile); // required from here
}
{
// noisy default usage
std::ofstream myFile("file.txt");
using boost::iostreams::tee;
using boost::iostreams::stream;
auto && myTee = stream<decltype(tee(std::cout, myFile))>(tee(std::cout, myFile));
}
return 0;
}
Error from clang++ --std=c++11 teetest.cpp is:
teetest.cpp:14:12: error: call to implicitly-deleted copy constructor of 'boost::iostreams::stream<boost::iostreams::tee_device<basic_ostream<char>, basic_ofstream<char> > >'
Compile fine in c++17 with "guaranty copy elision".
In c++11, you might use return {..}:
template <typename StreamT1, typename StreamT2>
boost::iostreams::stream<boost::iostreams::tee_device<StreamT1, StreamT2> >
make_tee(StreamT1 & t1, StreamT2 & t2)
{
using boost::iostreams::stream;
using boost::iostreams::tee;
return {tee(t1,t2)};
}
Demo
I have not managed to find why this code does not
work:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
auto xClosure = [](const function<void(int&)>& myFunction) {
myFunction(10);};
xClosure([]
(int& number) -> void
{cout<<number<<endl;
});
return 0;
}
It returns:
g++ test.cc -o test -std=c++14
test.cc:9:5: error: no matching function for call to object of type 'const function<void
(int &)>'
This has nothing to do with lambdas:
void test(const function<void(int&)>& myFunction) {
myFunction(10);
}
this fails to compile for the same reason; you cannot bind the literal 10 to an int&.
Maybe you meant
const function<void(int)>& myFunction
doing so and also modifying the signature of your lambda should make your code compile.
This small test program:
#include <functional>
//template<class T> // <-- with this, gcc compiles ok
template<class T=void>
struct c{
std::function<int(int)> f = [](int i){return i+i;};
};
int main() {};
Clang-3.2 compiles it ok, but from GCC 4.7.1 and 4.8 I am getting strange error:
t.cc:6:31: error: default argument for template parameter for class enclosing ‘struct __lambda0’
function<int(int)> f = [](int i){return i+i;};
^
Is this one of those obscure C++ rules exceptions that nobody knows about or is it a GCC bug?
EDIT
Looks like a bug. I've filed bug report
I think this is a g++ bug with default member initialization. I'm not positive about this, and so have the following supporting evidence:
template<class T=void>
struct c {
std::function<int(int)> f;
c() : f([](int i){return i+i;}) {
}
};
int main() {}
If that works, what you're doing should work too. And it does, even if you construct a c.
Personally, I think default member initialization should be used sparingly and with care. I think it's really easy to create a lot of confusion with it because most people expect all the initialization to be done in the constructor, and member initializers are not necessarily anywhere near any constructor. So they can leave someone scratching their head wondering how some member gets a particular value.
I can see cases, especially with simple, mostly-data classes for which it would work pretty well. But mostly, I think if you have a constructor body of any kind, you should probably not be using default member initialization.
This code will get error anyway on gcc. Yes, without default argument it can be compiled. It can be compiled because struct c isn't used anywhere. But if you try to create instance of this struct, you will get error.
#include <functional>
template<class T>
struct c {
std::function<int(int)> f = [](int i){return i+i;};
};
int main() {
c<int> _c; // error
}
It looks like a bug of gcc. This way can help to avoid problem.
#include <functional>
#include <iostream>
template<class T=void>
struct c {
c() : f([](int i){return i+i;}) {
}
std::function<int(int)> f;
};
int main() {
c<> _c;
std::cout << _c.f(10) << std::endl;
}