使用Lambda函数的模板转换失败

时间:2013-05-21 23:10:19

标签: c++ templates c++11 lambda

Hy @ all, 我们必须实现以下功能调用:

std::mt19937 engine;
color_table lut = create_random_color_map(engine);



发动机必须是可更换的。我们试图用这种方式实现它:
*。HPP

#include <tuple>
#include <random>

typedef std::tuple<unsigned char,unsigned char,unsigned char> rgb_tuple;

class color_table{
    public:
        [...]
        void generate(rgb_tuple predicate(const unsigned char& index));





 };
template <class RANDOM>
static rgb_tuple random_color(RANDOM engine){
    std::uniform_int_distribution<int> dist1 (0,255);
    unsigned char red   = (unsigned char) dist1();
    unsigned char green = (unsigned char) dist1(engine);
    unsigned char blue  = (unsigned char) dist1(engine);
    return std::make_tuple(red, green, blue);
}

template <class RANDOM>
static color_table create_random_color_map(RANDOM engine){
    color_table lut;
    lut.generate([&](const unsigned char& i)->rgb_tuple {
        return random_color<decltype(engine)>(engine);
    } );
    return lut;
}

*的的.cpp

...
void color_table::generate(rgb_tuple predicate(const unsigned char& index)){
    for(int i = 0; i < 256; ++i){
        std::tie(red_table[i], green_table[i], blue_table[i]) = predicate(i);
    }
}

当我们尝试编译时,会发生以下错误:

  

错误C2664:'color_table :: generate':转换参数1   从   'create_random_color_map ::'   'rgb_tuple(__ cdecl *)(const unsigned char&amp;)'不可能1&gt;

  没有用户定义的convertionoperator,可以执行   转换或运算符不能被调用。 ...   功能模板“color_table   create_random_color_map(RANDOM)“。与[
  RANDOM = std :: mt19937]

我们对这种失败完全无能为力,谷歌在这种情况下不是我们的朋友! :/

我们感谢任何帮助!

此致 希密尔

2 个答案:

答案 0 :(得分:3)

第一个(主要)问题:

您的函数generate()接受函数指针作为其参数,并且您正在尝试传递捕获lambda。不幸的是,捕获lambda不能隐式转换为函数指针。根据C ++ 11标准的5.1.2 / 6段:

  

没有 lambda-capture lambda-expression 的闭包类型具有公共非虚拟非显式const   转换函数指向函数,该函数具有与闭包类型相同的参数和返回类型   函数调用运算符。此转换函数返回的值应为函数的地址   当被调用时,它与调用闭包类型的函数调用操作符具有相同的效果。

您可以更改设计并让generate()成为函数模板,接受可调用对象作为其参数:

 class color_table{
    public:
        template<typename P>
        void generate(P predicate);
 };

或者,您可以使用std::function包装器来实现灵活性,而不会重复使用模板(但需要一些运行时开销):

#include <functional> // <== NEEDED FOR std::function

class color_table{
    public:
        void generate(std::function<rgb_tuple(const unsigned char&)> predicate);
};

这是一个live example,显示使用上述解决方案编译的代码。

第二(次要)问题:

您不应明确指定random_color()的模板参数。而是让编译器完成其工作并执行类型推导:

lut.generate([&](const unsigned char& i)->rgb_tuple {
    return random_color(engine);
//         ^^^^^^^^^^^^^^^^^^^^^
});

答案 1 :(得分:0)

我认为问题在于你:

void generate(rgb_tuple predicate(const unsigned char& index));

应该是:

void generate(rgb_tuple (*predicate)(const unsigned char& index));

你不能传递函数!只是指向函数的指针。

但是唉! lambda只能转换为指向函数的指针,如果它们有一个空捕获集,而lambda则没有。

所以你可以试试std::function

void generate(std::function<rgb_tuple(const unsigned char& index)> predicate);

PS:有点解释是......你的错误信息是:

  

将参数1从'create_random_color_map ::'转换为'rgb_tuple(__ cdecl *)(const unsigned char&amp;)'不可能

第一部分create_random_color_map::是告诉你它不知道它试图转换的对象类型的VC ++方式,但它是create_random_color_map本地的东西:这显然是lambda本身。

第二部分rgb_tuple (__cdecl *)(const unsigned char &)只是指向适当类型函数的指针。

错误说第一个不能转换为后者。