2

I want to pass a lambda to a function, but I have run into a problem of successfully passing it onto the function. The function chooses to append TrueVal or FalseVal and creates a vector of boolean, based on the given condition.

I'm using 2019 Visual Studio's ISO C++14 Standard to compile the code.

#include <iostream>
#include <vector>

using namespace std;

template<typename T, typename T1, typename T2>
vector<bool> ConstructNestedVectorByElements(T condition, T1 TrueVal, T2 FalseVal) {
    vector<bool> TempCol;
        TempCol = {};
        for (int i = 0; i < 3; i++)
        {
            if (condition(i)) {
                TempCol.emplace_back(TrueVal);
            }
            else {
                TempCol.emplace_back(FalseVal);
            }
        }
    return TempCol;
}

int main()
{
    vector<int> NumList = { 0, 1, 2 };
    vector<bool> BoolList = {true, false, true};

    auto ElementIsZero = [&NumList](int i) {return NumList[i] == 0; };
    vector<bool> a = ConstructNestedVectorByElements(ElementIsZero, true, false); //this works

    auto OriginalElement = [&BoolList](int i) {return BoolList[i]; };
    vector<bool> b = ConstructNestedVectorByElements(ElementIsZero, true, OriginalElement); //error

    return 0;
};

The error message:

C2440 'initializing': cannot convert from 'T2' to 'bool' ...\include\vector line 2385

1>...\vector(2385,18): error C2440: 'initializing': cannot convert from 'T2' to 'bool'
1>        with
1>        [
1>            T2=main::<lambda_e116e485fb739b952327b9205614af81>
1>        ]
1>...\vector(2385,18): message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>...\Source.cpp(19): message : see reference to function template instantiation 'decltype(auto) std::vector<bool,std::allocator<bool>>::emplace_back<T2&>(T2 &)' being compiled
1>        with
1>        [
1>            T2=main::<lambda_e116e485fb739b952327b9205614af81>
1>        ]
1>...\Source.cpp(36): message : see reference to function template instantiation 'std::vector<std::vector<bool,std::allocator<bool>>,std::allocator<std::vector<bool,std::allocator<bool>>>> ConstructNestedVectorByElements<main::<lambda_52b07f243bfcbbd5a342ddead4700eca>,bool,main::<lambda_e116e485fb739b952327b9205614af81>>(T,T1,T2)' being compiled
1>        with
1>        [
1>            T=main::<lambda_52b07f243bfcbbd5a342ddead4700eca>,
1>            T1=bool,
1>            T2=main::<lambda_e116e485fb739b952327b9205614af81>
1>        ]
template <class... _Valty>
    decltype(auto) emplace_back(_Valty&&... _Val) {
        bool _Tmp(_STD forward<_Valty>(_Val)...);
        push_back(_Tmp);

I think the problem might be one of the following:

  • I'm passing more than one type of argument into T2 (a lambda and a bool): Perhaps I used the wrong keyword, typename, to initialize T2? I tried with class but the same thing occurred.
  • OriginalElement isn't given parameters when it requires them: This confuses me a bit. If I change the line to:
TempCol.emplace_back(FalseVal(i, j)); //this is line 19

This error shows up:

C2064 term does not evaluate to a function taking 2 arguments ...\Source.cpp line 19

However, this seems not to be the case for condition(i, j), which compiles correctly. Is there a difference in handling (what I assume to be) boolean when in a conditional, and when appending it to a vector?

  • Lambdas not being constexpr, so it can't be used in templates: I don't really understand it, but there seems to be some relationship with this topic: (1, 2, 3)
2
  • 1
    Well what do you expect? In the one scenario T2 == bool and in the other T2 == lambda(x). But in both cases you try to push that value to a vector<bool>. Commented Jul 6, 2021 at 7:55
  • 1
    When you call .emplace_back(.., .., ..) instead of .. you pass some values that are used as the respective arguments of some constructor of your vector's type. In your case compiler tries to construct a bool (because that's type of element of TempCol), and as an argument of constructor your pass a lambda object. There's no such constructor of bool Commented Jul 6, 2021 at 7:56

1 Answer 1

1

The issue is that OriginalElement is not a bool and cannot be implicitly converted to one. You can call it to get a bool by passing an int. Change this line in the template:

TempCol.emplace_back(FalseVal(i));

then

auto OriginalElement = [&BoolList](int i) {return BoolList[i]; };
vector<bool> b = ConstructNestedVectorByElements(ElementIsZero, true, OriginalElement);

Compiles fine, but passing false will not work, because false is not a callable. T2 cannot be both, a callable and a bool. If you want both instantiations to work, you can change the first to

auto ElementIsZero = [&NumList](int i) {return NumList[i] == 0; };
vector<bool> a = ConstructNestedVectorByElements(ElementIsZero, true, [](int){ return false;});

Complete Demo

However, I suggest you to write two overloads. One that takes a callable. And to avoid the overhead of the callable, another one that takes a plain bool (no template parameter, let the conversion happen on the caller).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.