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

时间:2010-05-12 05:49:03

标签: c++ pass-by-reference optional-parameters

我遇到了C ++中可选功能参数的问题

我要做的是编写带有可选参数的函数,该函数通过引用传递,这样我就可以用两种方式(1)和(2)来使用它,但是在(2)我不是真的关心mFoobar的价值是什么。

我尝试过这样的代码:

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;
}

但它崩溃了

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

带有消息:

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

是否可以在没有函数重载的情况下解决它?

11 个答案:

答案 0 :(得分:37)

不要对可选参数使用引用。没有引用NULL的概念:引用始终是特定对象的别名。

或许请查看boost::optionalstd::experimental::optionalboost::optional甚至专门用于参考类型!

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

答案 1 :(得分:30)

为什么不能使用函数重载?当然,这是解决问题的最简单方法吗?

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

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

答案 2 :(得分:28)

(可变)引用的默认参数必须是l值。我能想到的最好,没有超载,

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

答案 3 :(得分:5)

另一种方法是使用指针而不是引用。这提供了您想要的语义而不会重载。 (就个人而言,我可能会超载。)

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

   // ...

   foo(&mBar, &mFoobar);

   // ...

   foo(&mBar);

   // ...

答案 4 :(得分:3)

这是另一种不会导致内存泄漏的疯狂方式,你不应该在现实生活中使用它,但乍看之下似乎是标准兼容并且使用Visual C ++ 2008&amp;在Cygwin下的g ++ 3.4.4:

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

重申:不要这样做!有更好的选择!超载可以成为您的朋友!但是,如果你是愚蠢和谨慎的话,你可以做到。 :)

答案 5 :(得分:1)

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

答案 6 :(得分:0)

就面向对象范式而言:如果给定的类具有&#34;默认&#34;,则必须相应地声明此默认值,然后可以将其用作&#34;默认参数&#34; 例如:

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;
    }
};

关于你的方法...

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

编辑:此解决方案非常合适,因为在这种情况下,它是一个&#34;全局默认&#34;分页和单个&#34;参考&#34;值。您还可以更改默认值,例如导航/显示首选项等。

Edit2:拼写和修复......

答案 7 :(得分:0)

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

答案 8 :(得分:0)

要使用标准库安全地执行此操作,您需要将 std::optionalstd::reference_wrapper 结合使用。 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
    }
}

这对被调用者是完全透明的。您可以像往常一样调用这样的函数:

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

这种方法的优点是它有一个空值来指示用户是否实际传递了一个引用。使用 -O2/-O3,它还可以在没有运行时成本的情况下进行非常巧妙的优化。

答案 9 :(得分:-1)

这是我解决此问题的方法:

我的原始函数没有返回的错误字符串: bool MyClass :: validateXML(const QString&fileName,const QUri&schemaUri);

我想将验证结果添加到错误字符串中,因此我实现了: bool MyClass :: validateXML(const QString&fileName,                     const QUri&schemaUri,                     QString&errorString = *(std :: make_unique()。get()));

这样,您可以在validateXML中引用errorString,而无需检查它是否有效,并且没有内存泄漏。

答案 10 :(得分:-4)

你可以这样疯狂:

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

P.S。 - 我知道它不愉快,但它的方式。另外一定不要留下内存泄漏! :))