对可变参数模板函数的模糊调用

时间:2015-04-19 11:39:10

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

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

//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();
}

编辑:整个背景不是很重要。我只需要知道如何重载variadic模板方法,其中重载版本仅与参数类型相互不同。

4 个答案:

答案 0 :(得分:1)

根据您的描述,我猜您需要lambda expression以上的可变参数模板。例如:

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

答案 1 :(得分:1)

如果SFINAE不符合你想要的任何预先要求,你可以将其中一个超载。

答案 2 :(得分:1)

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

回答你的问题:你不能以这种方式重载方法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<X&>(var)获取类型为Variable<X>& var的具体参数。

建议(2)

使用enable_ifdisable_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必须是接受可变参数模板的任何元方法,并且在所有类型都是标量(数字)的情况下定义静态布尔成员值。

答案 3 :(得分:0)

据我所知,仍然无法通过返回值消除歧义方法(尽管可以通过模板参数消除歧义)。如果你想保留语法,你可能想把方法创建一个函数到一个单独的对象中来调用它。