简体   繁体   English

Stl算法作为功能模板

[英]Stl algorithms as function template

I am trying to do a benchmark of stl algorithm on some structures : 我正在尝试在某些结构上做stl算法的基准测试:

using namespace std;

template<typename A, typename T>
void test(){
    T c(1000);
    A(c.begin(), c.end(), true);

}
int main(){
    test<find,vector<bool>>();
}

but I get a template argument deduction/substitution failed 但是我得到template argument deduction/substitution failed

The compilation error itself was well discussed in other answers. 编译错误本身在其他答案中得到了很好的讨论。 I present a solution with C++14 generic lambdas: 我提出了使用C ++ 14通用lambda的解决方案:

template<typename Container, typename Algorithm>
void test(Algorithm algo = Algorithm()){
    Container c(1000);
    algo(c.begin(), c.end(), true);
}

int main(){
    auto find_proxy = [](auto ... args){ return std::find(args...); };
    test<std::vector<bool>>(find_proxy);
}

Everyone's answer are good, but let me just add another note. 每个人的回答都很好,但让我再添加一个便条。

To make your code just work without changing much.. This is what has to happen. 为了使您的代码可以正常工作而无需进行太多更改。这就是必须要做的。

#include <vector>
#include <algorithm>

template< typename SearchFunctionType, typename ContainerType >
void test( SearchFunctionType fSearch, const ContainerType& container){
    fSearch(container.begin(), container.end(), true);
}

int main(){
    std::vector<bool> v(1000);
    test(std::find<std::vector<bool>::const_iterator, bool>, v);
}

std::find is not type as pointed out by everyone. std :: find不是每个人都指出的类型。 std::find is a function. std :: find是一个函数。 You may pass it as a function pointer. 您可以将其作为函数指针传递。 Then look, std::find is again template function, and compiler has no clue what template argument that std::find will have. 然后看一下,std :: find还是模板函数,编译器不知道std :: find将具有什么模板参数。 That's why you don't just pass std::find. 这就是为什么您不仅仅传递std :: find的原因。 instead , 相反,

std::find<std::vector<bool>::const_iterator, bool>.

Edit: 编辑:

#include <algorithm>
#include <vector>


template < typename ContainerType
         , typename ContainerType::const_iterator (*fpSearchFunction) (typename ContainerType::const_iterator, typename ContainerType::const_iterator, const typename ContainerType::value_type&) >
void test(const ContainerType& c, const typename ContainerType::value_type& value)
{
    fpSearchFunction(c.begin(), c.end(), value);
}


int main()
{
    std::vector<bool> v(1000);
    test< std::vector<bool>, std::find<std::vector<bool>::const_iterator, bool> >(v, true);
}

This works on VisualC. 这适用于VisualC。 Yes. 是。 integer type or function pointer can be template argument too. 整数类型或函数指针也可以是模板参数。 I bet there is better way than this. 我敢打赌,还有比这更好的方法。

Edit 2: 编辑2:

Although I don't see why having it templetized is preferable than just hard coding, This is what I would do if I do make some complication. 尽管我不明白为什么将其模板化比仅使用硬编码更可取,但是如果我做些复杂的事情,这就是我要做的。

#include <vector>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <cstdlib>
#include <functional>

template <typename ContainerType>
class Benchmark
{
public:
    typedef typename ContainerType::const_iterator  ConstIteratorType;
    typedef typename ContainerType::value_type      ValueType;
    typedef std::function < ConstIteratorType(ConstIteratorType, ConstIteratorType, const ValueType&) >
        SearchFunctionType;
    typedef std::chrono::high_resolution_clock      ClockType;

    void TestAll(const ContainerType& container, const ValueType& serachVal)
    {
        for (std::size_t i = 0; i < m_functions.size(); ++i)
        {




            ClockType::time_point begin = ClockType::now();
            m_functions[i](container.begin(), container.end(), serachVal);
            ClockType::duration duration = ClockType::now() - begin;
            std::cout << i << " : " << duration.count() << std::endl;
        }
    }

    void PushBack(SearchFunctionType fSearch)
    {
        m_functions.push_back(fSearch);
    }
private:
    std::vector<SearchFunctionType> m_functions;
};

int main(){

    typedef Benchmark<std::vector<bool>> BenchmarkType;
    BenchmarkType benchmark;
    benchmark.PushBack(std::find<BenchmarkType::ConstIteratorType, BenchmarkType::ValueType>);
    benchmark.PushBack([](BenchmarkType::ConstIteratorType begin, BenchmarkType::ConstIteratorType end, const BenchmarkType::ValueType& v)
    {
        BenchmarkType::ConstIteratorType iter;
        do
        {
            iter = begin + std::rand() % (end - begin);
            if (*iter == v)
                return iter;
        } while (iter != end);
        return end;
    });
    struct BinarySearch
    {
        BenchmarkType::ConstIteratorType operator()(BenchmarkType::ConstIteratorType begin, BenchmarkType::ConstIteratorType end, const BenchmarkType::ValueType& v)
        {


            return std::lower_bound(begin, end, v);
        }
    };
    benchmark.PushBack(BinarySearch());

    std::vector<bool> c;
    c.assign(10000, false);
    c.back() = true;

    benchmark.TestAll(c, true);

}

output: 输出:

0 : 100005
1 : 300017
2 : 0

问题是您尝试将模板作为模板参数传递,并希望将其推论-这将不起作用,因为编译器必须在某个时候开始填充类型: std::find不是typename ,但您需要成为一个!

Quite correctly so. 完全正确。 typename A requires a type name. 类型名typename A需要一个类型名。 std::find is not a type. std::find不是类型。 You probably want to pass A a as a regular argument, and then pass an instantiation of std::find . 您可能希望将A a作为常规参数传递,然后传递std::find的实例化。

Seems like you want to pass in a function to be executed on the instance of T ? 似乎您想传递要在T实例上执行的函数? But you cannot use a function template to substitute for the preprocessor. 但是您不能使用功能模板来代替预处理器。

find is the name of an algorithm, not a typename. find是算法的名称,而不是类型名。 You need to define a real type to be used as A , maybe a functor whose operator() executes std::find on its arguments. 您需要定义一个用作A的实类型,可能是一个函子,其operator()对其参数执行std::find

Suggest you get the logic working without A first and then extract A as a template parameter. 建议您先使逻辑在不使用A情况下工作,然后A提取为模板参数。 An incremental approach is often helpful in building complex class or function templates, and in general, but the compiler errors for broken template code can be especially confounding. 增量方法通常有助于构建复杂的类或函数模板,并且通常而言,但是损坏的模板代码的编译器错误尤其令人困惑。

You should check how it is already done in C++ library: 您应该检查C ++库中它是如何完成的:

template< class InputIt, class UnaryPredicate >
typename iterator_traits<InputIt>::difference_type
    count_if( InputIt first, InputIt last, UnaryPredicate p );

As you can see you have to provide functor type as a template parameter and functor instance as a function parameter. 如您所见,您必须提供函子类型作为模板参数,并提供函子实例作为函数参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM