简体   繁体   English

在 C++ 中通过引用传递可选参数

[英]Passing optional parameter by reference in c++

I'm having a problem with optional function parameter in C++我在 C++ 中遇到了可选函数参数的问题

What I'm trying to do is to write function with optional parameter which is passed by reference, so that I can use it in two ways (1) and (2), but on (2) I don't really care what is the value of mFoobar .我想要做的是编写带有通过引用传递的可选参数的函数,以便我可以通过两种方式(1)和(2)使用它,但是在(2)上我并不真正关心是什么mFoobar的值。

I've tried such a code:我试过这样的代码:

void foo(double &bar, double &foobar = NULL)
{
   bar = 100;
   foobar = 150;
}

int main()
{
  double mBar(0),mFoobar(0);

  foo(mBar,mFoobar);              // (1)
  cout << mBar << mFoobar;

  mBar = 0;
  mFoobar = 0;

  foo(mBar);                     // (2)
  cout << mBar << mFoobar;

  return 0;
}

but it crashes at但它崩溃了

void foo(double &bar, double &foobar = NULL)

with message :带有消息:

error: default argument for 'double& foobar' has type 'int'

Is it possible to solve it without function overloading?是否可以在没有函数重载的情况下解决它?

Don't use references for optional parameters.不要对可选参数使用引用。 There is no concept of reference NULL: a reference is always an alias to a particular object.没有引用 NULL 的概念:引用始终是特定对象的别名。

Perhaps look at boost::optional or std::experimental::optional .也许看看boost::optionalstd::experimental::optional boost::optional is even specialized for reference types! boost::optional甚至专门用于引用类型!

void foo(double &bar, optional<double &> foobar = optional<double &>())

Why can't you use function overloading?为什么不能使用函数重载? Surely it's the easiest solution to your problem?这肯定是解决您问题的最简单方法吗?

void foo(double &bar, double &foobar) 
{ 
   bar = 100; 
   foobar = 150; 
}

void foo(double &bar) 
{ 
   double foobar = 0.0;
   foo(bar, foobar);
}

The default argument of a (mutable) reference must be an l-value. (可变)引用的默认参数必须是左值。 The best I can think of, without overloading, is我能想到的最好的,没有超载,是

static double _dummy_foobar;
void foo(double &bar, double &foobar = _dummy_foobar)

Another way to do this is to use pointers instead of references.另一种方法是使用指针而不是引用。 This provides the semantics that you want without overloading.这提供了您想要的语义而不会重载。 (Personally, I'd probably go with overloading.) (就我个人而言,我可能会选择超载。)

void foo(double* bar, double* foobar = 0)
{
   if (bar) *bar = 100;
   if (foobar) *foobar = 150;
}

   // ...

   foo(&mBar, &mFoobar);

   // ...

   foo(&mBar);

   // ...

Here is another crazy way that does not result in memory leaks, which you should never use in real life, but seems to be standard compliant at first glance and compiles with Visual C++ 2008 & g++ 3.4.4 under Cygwin:这是另一种不会导致内存泄漏的疯狂方式,您在现实生活中永远不应该使用它,但乍一看似乎符合标准,并在 Cygwin 下使用 Visual C++ 2008 & g++ 3.4.4 进行编译:

void foo(double &bar, double &foobar = (*((double*)0)))
{
   bar = 100;
   double* pfoobar = &foobar;
   if (pfoobar != 0)
       foobar = 150;
}

To reiterate: DON'T DO THIS!重申:不要这样做! THERE ARE BETTER OPTIONS!有更好的选择! OVERLOADING CAN BE YOUR FRIEND!超载可以成为你的朋友! But yeah, you can do it if you're foolish and careful.但是,是的,如果您既愚蠢又小心,就可以做到。 :) :)

使用指针类型并将其设置为 NULL 比为引用参数设置默认/可选值要容易得多。

Speaking in terms of Object Oriented paradigm: If given class has and "Default", this Default must declared accordingly, and then may be used as an "Default Parameter" Ex:就面向对象范式而言:如果给定的类具有“默认值”,则必须相应地声明此默认值,然后可以将其用作“默认参数”例如:

class Pagination {
private:
    int currentPage;
public:

    //...
    Pagination() {
        currentPage = 1;
        //...
    }

    // your Default Pagination (Must be initialized before thread concurrency)
    static Pagination& Default() {
        static Pagination p; 
        return p;
    }
};

On your Method ...在你的方法...

     //...
     std::vector<User>
     findByFilter(User& audit, Pagination& p = Pagination::Default() ) {
     // ...

Edited: This solution is quite suitable since in this case it is an "global default" Pagination and a single "reference" value.编辑:此解决方案非常合适,因为在这种情况下它是“全局默认”分页和单个“参考”值。 You will also have the power to change default values such as navigation/display preferences and etc.您还可以更改默认值,例如导航/显示首选项等。

Edit2: spelling and fixing... Edit2:拼写和修复...

To do this safely with the standard library, you'll need to use std::optional in conjunction with std::reference_wrapper .要使用标准库安全地执行此操作,您需要将std::optionalstd::reference_wrapper结合使用。 Optional references of the form std::optional<T&> are illegal in C++17.形式std::optional<T&>可选引用在 C++17 中是非法的。

#include <optional>
#include <functional>

void foo(double& bar, std::optional<std::reference_wrapper<double>> foobar = {})
{
    if(foobar) // If the user has passed a reference
    {
        foobar->get() = 1.0; // Assign values to the reference
    }
}

This is completely transparent to the callee.这对被调用者是完全透明的。 You can call such a function as you would normally:您可以像往常一样调用这样的函数:

double a {}, b {};
foo(b, a);
std::cout << a; // Prints 1.0;

The advantage of this approach is that it has a null value to indicate if the user has actually passed a reference or not.这种方法的优点是它有一个空值来指示用户是否实际传递了一个引用。 With -O2/-O3, it also optimises away pretty neatly with no runtime cost.使用 -O2/-O3,它还可以在没有运行时成本的情况下非常巧妙地优化掉。

Starting with C++17, you may use parameter pack to implement this without manual overload, and without runtime overhead, like this:从 C++17 开始,您可以使用参数包来实现这一点,无需手动重载,也无需运行时开销,如下所示:

template <typename... OptArgType> void foo(double &bar, OptArgType&... foobar)
{
   static_assert(sizeof...(OptArgType) <= 1 && (std::is_same_v<OptArgType, double> && ...));
   bar = 100;
   ((foobar = 150), ...); // use fold expression for assignment
}

No "is this argument provided" check would be needed at runtime, the fold expression will expand to the code only for invocations actually passing the argument to the function.在运行时不需要“是否提供此参数”检查,折叠表达式将扩展为代码,仅用于实际将参数传递给函数的调用。

Alternatively to the static_assert , the check for the argument correctness may be inplemented using std::enable_if .替代static_assert ,可以使用std::enable_if来实现对参数正确性的检查。

void foo(double &bar,
         double &foobar = const_cast<double &>(static_cast<const double &>(0.0)))
{
   bar = 100;
   foobar = 150;
}

This is how I solved this question:我是这样解决这个问题的:

My original function didn't have a returned error string: bool MyClass::validateXML(const QString& fileName, const QUri& schemaUri);我的原始函数没有返回错误字符串: bool MyClass::validateXML(const QString& fileName, const QUri& schemaUri);

I wanted to add the results of the validation in an error string so I implemented: bool MyClass::validateXML(const QString& fileName, const QUri& schemaUri, QString& errorString = *(std::make_unique().get()));我想在错误字符串中添加验证结果,所以我实现了: bool MyClass::validateXML(const QString& fileName, const QUri& schemaUri, QString& errorString = *(std::make_unique().get()));

This way, you can reference the errorString in validateXML without checking if it's valid, and no memory leaks.这样,您就可以在validateXML 中引用errorString,而无需检查它是否有效,也不会出现内存泄漏。

You can do this crazy way:你可以这样做疯狂的方式:

void foo(double &bar, double &foobar = (*(new double())))

PS - I know its not pleasant but its the way. PS - 我知道它不愉快,但它的方式。 Also be sure not to leave memory leaks!另外一定不要留下内存泄漏! :)) :))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM