【问题标题】:Deduction template argument C++演绎模板参数 C++
【发布时间】:2011-12-14 09:19:30
【问题描述】:

请考虑下面的代码:

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 中那样的模板参数。

【问题讨论】:

  • 类在这里没有帮助,因为模板参数推导对它们不起作用。您的问题本质上归结为根据返回类型推断参数类型,这是不可能的。
  • function3(function2&lt;char&gt;()); 有什么问题?
  • 你能改一下function3还是那是刻在石头上的?
  • 你能解释一下function2的定义吗?我以为我是一个称职的 C++ 程序员,但我完全无法解析。
  • @jalf:这是一个函数,它返回一个指向函数的指针,该函数获取T 并返回bool。如果你不能立即解析它,我认为这表明你确实是一个优秀的 C++ 程序员(我不得不回到 C-days 的深处才能弄清楚)。

标签: c++ templates


【解决方案1】:

无法从返回类型中扣除。所以function2不能从你期望的返回类型中推断出来。

但是可以推导出强制转换运算符。 所以你可以用一个辅助结构替换function2,比如: 不幸的是,没有标准语法可以在没有 typedef 的情况下将强制转换运算符声明为函数指针,并且类型推导无法通过 typedef 工作。以下定义适用于某些编译器(适用于 G++ 4.5,不适用于 VC++ 9):

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

(另见C++ Conversion operator for converting to function pointer)。

调用应该看起来还是一样的。

注意: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:谢谢。我将语法修复到它在 gcc 中正常工作的程度,但在 vc++ 中似乎根本不可能。
【解决方案2】:

编译器不使用表达式的上下文来推断其模板参数。对于编译器,function3(function2()); 看起来像

auto tmp = function2();
function3(tmp);

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

【讨论】:

  • 这就是为什么我们必须为 lambdas 指定参数类型 - [](int x){},而不是 [](x){}
【解决方案3】:

编辑后,我认为您想做的事情可以做得更简单。请参阅以下类型:

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

现在,在您的operator&lt; 中,您根据参数的顺序返回一个无类型 Cmp 实例,即m_2 &lt; m_1 将返回Cmp(true)m_1 &lt; m_2 将返回@987654327 @。

由于有一个模板化的operator(),编译器将在sort 中推断出正确的函数,而不是在您调用sort 时。

【讨论】:

    【解决方案4】:

    我不确定这是否对您有帮助,而且我不是这方面的专家。从昨天开始我就一直在看这个帖子,我想参加这个。

    模板无法推断出它的类型,因为编译器不知道您期望返回什么类型。以下是一个与您的 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;
    

    我知道这很简单,每个人都知道这一点。由于没有人发布此内容,我想尝试一下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-12
      • 1970-01-01
      • 2019-08-04
      • 2020-05-09
      • 2019-09-23
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多