Ad

Std::barrier Is_nothrow_invocable_v Shall Be True Error

- 1 answer

I am trying to simulate a dice roll program, to be more specific get the number of rolls necessary to get n dices to be 6 at the same time.

So this is a textbook example of fork-join model in order to simulate rolls simultaneously and then check result after each iteration.

#include <iostream>
#include <vector>
#include <thread>
#include <random>
#include <array>
#include <barrier>

auto random_int(int min, int max)
{
    static thread_local auto engine = std::default_random_engine{ std::random_device{}() };
    auto dist = std::uniform_int_distribution<>(min, max);
    return dist(engine);
}

int main()
{
    constexpr auto n = 5;
    auto done = false;
    auto dice = std::array<int, n>{};
    auto threads = std::vector<std::thread>{};
    auto n_turns = 0;

    auto check_result = [&]
    {
        ++n_turns;
        auto is_six = [](int i) {return 6 == i; };
        done = std::all_of(std::begin(dice), std::end(dice), is_six);
    };

    auto bar = std::barrier{ n,check_result };

    for (int i = 0; i < n; ++i)
    {
        threads.emplace_back([&, i]{
                while (!done)
                {
                    dice[i] = random_int(1, 6);
                    bar.arrive_and_wait();
                }});
    }

    for (auto&& t : threads)
    {
        t.join();
    }

    std::cout << n_turns << std::endl;
}

And I am getting the following error:

error C2338: N4861 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunction&> shall be true 1>C:\Users\eduar\source\repos\C++20\C++20\main.cpp(114): message : see reference to class template instantiation 'std::barriermain::<lambda_1>' being compiled

Can someone please hint what am I doing wrong and how to fix this?

Ad

Answer

The issue is in the error message. Which is great, even cites exactly the part of the standard which has this requirement: [thread.barrier.class]/5:

CompletionFunction shall meet the Cpp17MoveConstructible (Table 28) and Cpp17Destructible (Table 32) requirements. is_­nothrow_­invocable_­v<CompletionFunction&> shall be true.

You're currently missing the last part: your lambda isn't nothrow-invocable. That's an easy fix tho:

auto check_result = [&]() noexcept
//                        ^~~~~~~~
{
    ++n_turns;
    auto is_six = [](int i) {return i == 6; };
    done = std::all_of(std::begin(dice), std::end(dice), is_six);
};

I also took the opportunity to flip your Yoda conditional, because there is no reason to write Yoda conditionals.

Ad
source: stackoverflow.com
Ad