【问题标题】:Ambiguous call to variadic template function对可变参数模板函数的模糊调用
【发布时间】:2015-04-19 11:39:10
【问题描述】:

我正在创建一些以数学意义表示函数的类,它们的界面是“数学友好的”。为此,我想创建一个可变参数模板 operator() 方法,它允许用户以这种方式编写定义函数f(x, y) = 2*x + y;,然后通过调用f(4, 5); 获取其值。我无法预测参数的数量(数学函数中的变量数量),所以我决定使用可变参数模板。但是,将 operator() 两次重载为可变参数模板并调用它会导致“模糊调用”错误。有什么方法可以克服它,还是我必须创建两个单独的方法?

//expressions like f(x, y, z) = x*x+y-z    
template <typename... Args>
RichFunction<T> &operator()(Args&&... args)
{
        mMainLinears.clear();
        setMainLinears(args...);
        return *this;
}

//expressions like f(5, 4, 3)
template <typename... Args>
T operator()(Args&&... args)
{
    Function<T>::assign(mMainLinears, 0, args...);
    return Function<T>::value();
}

编辑:整个背景不是很重要。我只需要知道如何重载可变参数模板方法,其中重载版本仅在参数类型上有所不同。

【问题讨论】:

  • 不返回*this,在第一个示例中返回不同的类型?或者根本不需要第一个?还是做 sfinae 类型检查?
  • @Rames 您可以按照建议使用一些基本的 sfinae like here

标签: c++ c++11 variadic-templates


【解决方案1】:

根据您的描述,我猜您需要lambda expression 而不是可变参数模板。举例说明:

auto f = [](double x, double y) { return 2 * x + y; };
std::cout << f(4, 5) << '\n';

【讨论】:

  • 不,我完全不是这个意思。也许我的描述不够清楚......代码 sn-p 显示来自 RichFunction 类的方法
【解决方案2】:

如果其中一个重载不满足您想要的任何先决条件,您可以 SFINAE 消除它。

【讨论】:

    【解决方案3】:

    如果我理解正确,第一个 operator() 应该定义你的数学表达式,第二个应该评估之前定义的这个表达式。

    回答您的问题:您不能以这种方式重载方法 operator(),因为两种方法中的签名是相同的,即完全相同的模板定义和参数列表。编译器应该如何知道调用哪个方法?必须有办法区分这两种调用。

    解决方案的建议(1)

    您的变量 (x,y,z) 可能属于某种类型。你可以使用 CRTP 模式来定义一个通用的基类

    template <class Sub>
    struct Variable {};
    
    struct X : Variable<X> {};
    struct Y : Variable<Y> {}; //...
    

    然后你可以基于这个类结构做一个重载:

    template <class... Xs>
    ReturnType operator()(Variable<Xs>&&... vars) {...}
    

    在此方法中,您可以强制转换为具体的变量类型,例如通过使用static_cast&lt;X&amp;&gt;(var) 来作为Variable&lt;X&gt;&amp; var 类型的具体参数。

    建议(二)

    使用enable_if 和disable_if(来自boost 或std)来区分传递给方法的两种参数类型,即

    template <class... Ts>
    typename enable_if< is_scalar<Ts...>, ReturnType>::type 
    operator()(Ts&&... values) { ... }
    
    template <class... Ts>
    typename disable_if< is_scalar<Ts...>, ReturnType>::type 
    operator()(Ts&&... vars) { ... }
    

    其中is_scalar 必须是任何接受可变参数模板并在所有类型都是标量(数字)的情况下定义静态布尔成员值的元方法。

    【讨论】:

    • 它们的参数列表不一样 - 一个是 Linear 类的对象,第二个是 T。我不知道如何在可变参数模板声明中明确说明它。但是第二种解决方案可能会起作用
    【解决方案4】:

    据我所知,仍然没有办法通过返回值来消除歧义(尽管您可以通过模板参数消除歧义)。如果您想保留语法,您可能希望将创建函数的方法放入与调用它的对象不同的对象中。

    【讨论】:

      猜你喜欢
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多