【问题标题】:<function-style-cast> error: Cannot convert from 'initializer list' to 'std::thread'<function-style-cast> 错误:无法从“初始化列表”转换为“std::thread”
【发布时间】:2016-07-20 08:59:16
【问题描述】:

我正在尝试使用 std::threads 并行化快速排序,但我收到一个我不熟悉的错误,因为我刚开始使用多线程。错误可能很简单,我一直跳过它。有人可以解释一下这个问题。这是代码和出现的唯一错误:

        #define _CRT_SECURE_NO_WARNINGS

#include <iostream> //cout, endl
#include <cstdlib>  //srand
#include <algorithm>//copy, random_shuffle
#include <iterator> //ostream_iterator
#include "ratio.h"
#include <vector>
#include <iostream>
#include <thread>
#include "quicksort.h"
#include "sort_small_arrays.h"

template< typename T>
unsigned partition(T* a, unsigned begin, unsigned end) {
    unsigned i = begin, last = end - 1;
    T pivot = a[last];

    for (unsigned j = begin; j<last; ++j) {
        if (a[j]<pivot) {
            std::swap(a[j], a[i]);
            ++i;
        }
    }
    std::swap(a[i], a[last]);
    return i;
}

/* iterative */
#define STACK
#define xVECTOR
#define xPRIORITY_QUEUE 

#include <utility> // std::pair

template <typename T>
using triple = typename std::pair< T*, std::pair<unsigned, unsigned>>;

template< typename T>
struct compare_triples {
    bool operator() (triple<T> const& op1, triple<T> const& op2) const {
        return op1.second.first > op2.second.first;
    }
};

#ifdef STACK
#include <stack>
template< typename T>
using Container = std::stack< triple<T>>;
#define PUSH push
#define TOP  top
#define POP  pop
#endif

#ifdef VECTOR
#include <vector>
template< typename T>
using Container = std::vector< triple<T>>;
#define PUSH push_back
#define TOP  back
#define POP  pop_back
#endif

#ifdef PRIORITY_QUEUE
#include <queue>
template< typename T>
using Container = std::priority_queue< triple<T>, std::vector<triple<T>>, compare_triples<T> >;
#define PUSH push
#define TOP  top
#define POP  pop
#endif

//Thread quicksorts a single range of elements and decrements thread counter at the end
template< typename T>
void threadsort_iterative_aux(Container<T> & ranges, int &currentThreads)
{
    triple<T> r = ranges.TOP();
    ranges.POP();

    T*       a = r.first;
    unsigned b = r.second.first;
    unsigned e = r.second.second;

    //base case
    if (e - b<6) {
        switch (e - b) {
        case 5: quicksort_base_5(a + b); break;
        case 4: quicksort_base_4(a + b); break;
        case 3: quicksort_base_3(a + b); break;
        case 2: quicksort_base_2(a + b); break;
        }
        continue;
    }

    unsigned q = partition(a, b, e);

    ranges.PUSH(std::make_pair(a, std::make_pair(b, q)));
    ranges.PUSH(std::make_pair(a, std::make_pair(q + 1, e)));
    --currentThreads;
}

template< typename T>
void quicksort(T* a, unsigned begin, unsigned end, int num_threads)
{
    //Number of threads currently running other than the main thread
    int currentThreads = 0;

    //Ranges of elements to sort
    Container<T> ranges;
    ranges.PUSH(std::make_pair(a, std::make_pair(begin, end)));

    //Dynamic vector of threads
    std::vector<std::thread> threads;

    //Loops till all threads are done AND nothing left to sort
    while (!ranges.empty() || currentThreads != 0)
    {
        //Doesn't bother doing anything if the range is empty but other threads are still running
        if (!ranges.empty())
        {
            //If we can make more threads, make a thread and give it the top range to sort
            if (currentThreads < num_threads)
            {
                ++currentThreads;
                threads.push_back(std::thread(threadsort_iterative_aux, std::ref(ranges), std::ref(currentThreads)));

            }
            //Starts sorting itself if maximum number of threads are running
            else
            {
                triple<T> r = ranges.TOP();
                ranges.POP();
                T*       a = r.first;
                unsigned b = r.second.first;
                unsigned e = r.second.second;

                //Optimized sorting of a range between 2 and 5 elements
                if (e - b < 6) {
                    switch (e - b) {
                    case 5: quicksort_base_5(a + b); break;
                    case 4: quicksort_base_4(a + b); break;
                    case 3: quicksort_base_3(a + b); break;
                    case 2: quicksort_base_2(a + b); break;
                    }
                    continue;
                }

                unsigned q = partition(a, b, e);

                ranges.PUSH(std::make_pair(a, std::make_pair(b, q)));
                ranges.PUSH(std::make_pair(a, std::make_pair(q + 1, e)));
            }
        }
    }
}

template< typename T>
bool check_is_sorted(T* a, unsigned size)
{
    for (unsigned int i = 1; i<size; ++i) {
        if (!(a[i - 1] <= a[i])) {
            return false;
        }
    }
    return true;
}

bool test_int(unsigned size, unsigned num_threads) {
    int* a = new int[size];
    for (unsigned i = 0; i<size; ++i) { a[i] = i; }
    std::srand(static_cast<unsigned int>(std::time(NULL)));
    std::random_shuffle(a, a + size);
    quicksort(a, 0, size, num_threads);
    bool retval = check_is_sorted(a, size);
    delete[] a;
    return retval;
}

void test0() {
    if (test_int(200, 1)) { std::cout << "OK\n"; }
    else { std::cout << "Failed\n"; }
}

#include <cstdio>    /* sscanf */
int main(int argc, char ** argv) 
{
    test0();
    return 0;
}

严重性代码描述项目文件行 错误 C2440 '':无法从 'initializer list' 转换为 'std::thread' 第 145 行(包含:

threads.push_back(std::thread(threadsort_iterative_aux, std::ref(ranges), std::ref(currentThreads)));)

【问题讨论】:

    标签: c++ multithreading c++11 parallel-processing


    【解决方案1】:

    您在创建线程时将triple&lt;T&gt; 作为第一个参数传递给threadsort_iterative_aux,但该函数需要一个Container&lt;T&gt; &amp;

    另请注意,使用此签名通过非 const-reference 传递参数,您需要在调用方将参数包装在 std::ref() 中。

    这与std::bind 的行为基本相同:如果省略std::ref,编译器会将值复制到绑定中,然后在调用时将该副本作为参数传递给函数调用。由于副本是不可变的,因此会因非常量引用而中断。这是一件好事,因为它可以防止您意外丢失该参数的副作用。

    最后但同样重要的是,绑定机制打破了模板参数推导。由于您实际上并没有在创建线程时调用该函数,因此编译器无法自动从参数中推断出该函数的模板参数。您必须明确给出参数:

    threads.push_back(std::thread(threadsort_iterative_aux<T>, std::ref(ranges), std::ref(currentThreads)));
    //                               note the <T> here  ---^
    

    由于这些是一大堆令人头疼的问题,您可能只想使用 lambda,它不会遇到这些问题:

    threads.push_back(std::thread([&]() { threadsort_iterative_aux(ranges, currentThreads); }));
    

    【讨论】:

    • 嗯,我认为您的输入会修复错误。我将行更改为以下内容:threads.push_back(std::thread(threadsort_iterative_aux, std::ref(ranges), std::ref(currentThreads)));但同样的错误仍然存​​在。我做错了吗?或者您是否发现了我在修复错误后必须处理的错误?
    • @AmrotheStudent 该行现在看起来正确。不幸的是,您发布的代码不完整,因此很难进一步诊断错误。您能否编辑帖子以显示 a complete, self-contained example 并包含您从编译器获得的完整错误消息?
    • 好吧,我不确定要给你看多少,所以我拿出了我认为无关紧要的东西。我离开了驱动程序和主要功能,您现在应该可以复制粘贴并运行以查看相同的错误。如果代码仍然太多,我将重新编辑代码。
    • 好的,我把它做得更短,更“最小化”。
    • @AmrotheStudent 我编辑了答案。您发布的示例代码似乎存在一些不相关的小问题,但我认为您将能够自己解决这些问题:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 2015-10-10
    • 2021-01-25
    • 2018-06-02
    相关资源
    最近更新 更多