mlt
mlt

Reputation: 1669

How to emplace a function wrapper with some arguments from local variables into container with MSVC2015?

I was looking at an answer to another question. However I can't figure out, based on that example, why can't I bind a value of some local variable with MSVC 2015 compiler? It just throws an error while gcc 5.3 compiles it fine on msys2/mingw64. I mean like in

#include <iostream>
#include <functional>
#include <vector>

int add(int a, int b) { return a + b; }

using bound_add_t = decltype(std::bind(add, std::placeholders::_1, int()));

int main() {
  std::vector<bound_add_t> vec;
  int y = 2;
  vec.emplace_back(add,std::placeholders::_1, y); // <- this causes the problem
  vec.emplace_back(add,std::placeholders::_1, 2);
  vec.emplace_back(add,std::placeholders::_1, 3);

  for (auto &b : vec)
    std::cout << b(5) << std::endl;

  return 0;   
}

Severity Code Description Project File Line Suppression State Error C2664 'std::_Binder &,int>::_Binder(std::_Binder &,int> &&)': cannot convert argument 3 from 'int' to 'int &&' C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0 655

Is it a known issue tracked somewhere? I'm not even sure what is the underlying problem here. Is there a workaround?

In my use case, I'm missing one argument that becomes available later, so I'd want to have a vector with a wrapped function ready just like in that example.

Update

Is it a C++14 thing? I was poking around on http://ideone.com/Zi1Yht . While there is no MSVC, only compiler marked as C++14 was able to compile it.

Update 2

I tried

std::vector<std::function<int(int)> > vec;
vec.emplace_back(add, std::placeholders::_1, y);

if that was implied, I get

Severity Code Description Project File Line Suppression State Error C2664 'std::function::function(std::function &&)': cannot convert argument 1 from 'int (__cdecl &)(int,int)' to 'std::allocator_arg_t' C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xmemory0 655

Upvotes: 4

Views: 946

Answers (2)

Anton Savin
Anton Savin

Reputation: 41331

MSVC is in its right in rejecting this code. int() is a temporary and therefore corresponding Args&&... parameter is deduced as int&&. So the constructor of the result type of bind can take int&& as the last parameter, and y is not an rvalue so compilation fails.

This is not a bug in other compilers, because the result of bind is unspecified.

If you don't want to fall back to std::function you can enforce the type of the last parameter to be const int&:

using bound_add_t = decltype(std::bind(add, std::placeholders::_1, std::declval<const int&>()));

Upvotes: 1

Jarod42
Jarod42

Reputation: 218138

The return type of std::bind is unspecified.

The required constructor is the copy constructor or the move constructor.

Construct it from the arguments (function, placeholders, ...) you give is unspecified and may work for specific implementation but is not portable.

As a workaround, you may do

std::vector<std::function<int(int)> > vec;
int y = 2;

vec.push_back(std::bind(add, std::placeholders::_1, y));
vec.push_back(std::bind(add, std::placeholders::_1, 2));
vec.push_back(std::bind(add, std::placeholders::_1, 3));

Upvotes: 0

Related Questions