C++模板参数推导模板

6
请看下面的代码:

请看下面的代码:

template<typename T>
bool function1(T some_var) { return true; }

template <typename T>
bool (*function2())(T) {
  return function1<T>;
}

void function3( bool(*input_function)(char) ) {}

如果我调用
function3(function2<char>());

可以这样做。但是如果我调用

function3(function2());

编译器给出的错误是无法推断模板参数。请问您能否提供建议,如何重新编写function1和/或function2(也许,通过使用类从根本上进行重写)以使其可行?
*添加*
我正在尝试做一些简单的东西,比如在Boost.LambdaLib中使用lambda表达式(也许我走错了路)。
sort(some_vector.begin(), some_vector.end(), _1 < _2)

我做了这个:
template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

class my_comparing {
 public:
  int value;
  my_comparing(int value) : value(value) {}
  template <typename T>
  bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
    if (this->value == 1 && another.value == 2) {
      return my_func_greater<T>;
    } else {
      return my_func_greater<T>;
    }
  }
};

const my_comparing& m_1 = my_comparing(1);
const my_comparing& m_2 = my_comparing(2);

它能够正常工作:

sort(a, a + 5, m_1.operator< <int>(m_2));

但是我希望它不需要像LambdaLib那样需要模板参数。

3
类在这里没有帮助,因为模板参数推导不适用于它们。你的问题实质上归结为基于返回类型推断参数类型,这是不可能的。 - Björn Pollex
2
function3(function2<char>());有什么问题? - Ferdinand Beyer
3
那是一个返回函数指针的函数,这个函数所需的参数为一个 T 类型的变量,并返回一个 bool 类型的值。如果你不能立即解析它,我认为这表明你确实是一位优秀的 C++ 程序员(我不得不回到 C 语言时代深处才能理解它)。 - bitmask
哦,没错。是的,我现在看到了。谢谢 :) - jalf
@MatthieuM:在 C++11 中,可以使用尾返回类型(和/或decltype)来澄清声明。 - jalf
显示剩余6条评论
4个回答

5
编译器不使用表达式的上下文来推导其模板参数。对于编译器而言,function3(function2()); 看起来就像是:
auto tmp = function2();
function3(tmp);

它不知道 function2 模板参数是什么。


这就是为什么我们必须为lambda表达式指定参数类型 - [](int x){},而不是[](x){} - Abyx

5
无法从返回类型中推断出函数,因此无法从您期望的返回类型推断出function2
但是可以推断强制转换运算符。不幸的是,在没有typedef的情况下声明强制转换运算符到函数指针的标准语法不存在,并且类型推断不能通过typedef进行推断。以下定义在某些编译器中起作用(在G++ 4.5中有效,在VC++ 9中无效):
struct function2 {
    template <typename T>
    (*operator bool())(T) {
        return function1<T>;
    }
};

(参见C++转换运算符用于将其转换为函数指针)。

调用应该仍然保持相同。

注意:C++11引入了可模板化的替代typedef语法。它会像这样:

struct function2 {
    template <typename T>
    using ftype = bool(*)(T);

    template <typename T>
    operator ftype<T>() {
        return function1<T>;
    }
};

但是我手头没有G++ 4.7或VC++ 10,所以我无法测试它是否实际可行。


广告添加:

Boost.Lambda的技巧在于它不返回函数,而是返回函数对象。而函数对象可以是类模板。因此你可以这样写:

template<typename T>
bool function1(T some_var) { return true; }

class function2 {
    template <typename T>
    bool operator()(T t) {
        function1<T>;
    }
};

template <typename F>
void function3( F input_function ) { ... input_function(something) ... }

现在你可以写:

function3(function2);

它将解析function3内部的模板。所有STL都以函数对象作为模板,所以这将适用于所有STL。

然而,如果不想把function3作为模板,还有一种方法。与函数指针不同的是,std::function(仅限C++11,对于旧编译器请使用boost :: function )模板可以从任何函数对象(包括普通函数指针)构造。因此,给定上述内容,可以编写以下代码:

void function3(std::function<bool ()(char)> input_function) { ... input_function(something) ... }

现在,您仍然可以进行以下调用:

function3(function2());

要点在于 std::function 具有一个模板构造函数,该函数内部生成一个模板包装器,并存储指向其方法的指针,因此可以直接调用而无需进一步使用模板。

你可以请教一下,为什么这段代码在Visual Studio 2010里无法编译吗? - Programmer585
@Programmer585:谢谢。我已经修复了语法,现在在gcc中可以正常工作,但是在vc++中似乎根本不可能。 - Jan Hudec

2

在您编辑之后,我认为您想要做的事情可以更简单地完成。请参见以下类型:

struct Cmp {
  bool const reverse;
  Cmp(bool reverse) : reverse(reverse) {}
  template <typename T> bool operator()(T a, T b) {
    return reverse != (a < b);
  }
};

现在,在您的operator <中,根据参数的顺序返回一个非类型化Cmp实例,即m_2 < m_1将返回Cmp(true)m_1 < m_2将返回Cmp(false)。由于已放置了一个有模板的operator(),所以编译器将在sort中推断出正确的函数,而不是在调用sort时。请注意保留所有HTML标签。

1

我不确定这是否对您有所帮助,而且我也不是这方面的专家。自昨天以来,我一直在关注这篇文章,我想参与其中。

模板无法推断其类型,因为编译器不知道您期望返回什么类型。以下是一个类似于您的function2()的简单示例。

template<typename T>
T foo() {
    T t;
    return t;
};

呼叫此函数
foo(); // no type specified. T cannot be deduced.

是否可以将模板声明移动到类级别,如下所示:

template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

template <typename T>
class my_comparing {
public:
    int value;
    my_comparing(int value) : value(value) {}
    bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
        if (this->value == 1 && another.value == 2) {
            return my_func_greater<T>;
        } else {
            return my_func_greater<T>;
        }
    }
};

并按如下方式声明m_1和m_2:

const my_comparing<int>& m_1 = my_comparing<int>(1);
const my_comparing<int>& m_2 = my_comparing<int>(2);

现在你可以进行如下比较:

if( m_1 < m_2 )
    cout << "m_1 is less than m_2" << endl;
else
    cout << "m_1 is greater than m_2" << endl;

我知道这很简单,每个人都知道。但是因为没有人发布过,所以我想试一试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接