C++ 中默认参数值放在哪里?

发布于 2024-10-17 01:35:26 字数 36 浏览 1 评论 0原文

默认参数值在哪里?只是在函数定义或声明中,还是在两个地方?

What's the place for the default parameter value? Just in function definition, or declaration, or both places?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

不再见 2024-10-24 01:35:26

默认参数值必须出现在声明中,因为这是调用者看到的唯一内容。

编辑:正如其他人指出的,您可以对定义进行争论,但我建议编写所有代码,就好像这不是真的一样。

Default parameter values must appear on the declaration, since that is the only thing that the caller sees.

EDIT: As others point out, you can have the argument on the definition, but I would advise writing all code as if that wasn't true.

梦过后 2024-10-24 01:35:26

你可以选择其中之一,但不能两者兼而有之。通常您在函数声明时执行此操作,然后所有调用者都可以使用该默认值。但是您可以在函数定义中执行此操作,然后只有那些看到定义的人才能使用默认值。

You can do either, but never both. Usually you do it at function declaration and then all callers can use that default value. However you can do that at function definition instead and then only those who see the definition will be able to use the default value.

时光匆匆的小流年 2024-10-24 01:35:26

C++将默认参数逻辑放在调用端,这意味着如果不能从调用处计算出默认值表达式,则不能使用默认值。

其他编译单元通常只包含声明,因此放置在定义中的默认值表达式只能在定义编译单元本身中使用(并且在定义之后,即在编译器看到默认值表达式之后)。

最有用的地方是在声明 (.h) 中,以便所有用户都能看到它。

有些人也喜欢在实现中添加默认值表达式(作为注释):

void foo(int x = 42,
         int y = 21);

void foo(int x /* = 42 */,
         int y /* = 21 */)
{
   ...
}

但是,这意味着重复,并且会增加注释与代码不同步的可能性(什么比未注释的代码更糟糕?带有误导性注释的代码!)。

C++ places the default parameter logic in the calling side, this means that if the default value expression cannot be computed from the calling place, then the default value cannot be used.

Other compilation units normally just include the declaration so default value expressions placed in the definition can be used only in the defining compilation unit itself (and after the definition, i.e. after the compiler sees the default value expressions).

The most useful place is in the declaration (.h) so that all users will see it.

Some people like to add the default value expressions in the implementation too (as a comment):

void foo(int x = 42,
         int y = 21);

void foo(int x /* = 42 */,
         int y /* = 21 */)
{
   ...
}

However, this means duplication and will add the possibility of having the comment out of sync with the code (what's worse than uncommented code? code with misleading comments!).

冷情妓 2024-10-24 01:35:26

虽然这是一个“旧”线程,但我仍然想添加以下内容:

我经历了下一种情况:

  • 在类的头文件中,我有
int SetI2cSlaveAddress( UCHAR addr, bool force );
  • 在该类的源文件中,我有
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
   ...
}

正如您所看到的,我已将参数“force”的默认值放在类源文件中,而不是类头文件中。

然后我在派生类中使用该函数,如下所示(派生类以公共方式继承基类):

SetI2cSlaveAddress(addr);

假设它将“force”参数视为“false”“理所当然”。

但是,编译器(置于 c++11 模式)抱怨并给了我以下编译器错误:

/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
                 from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2

但是当我在 中添加默认参数时基类的>头文件

int SetI2cSlaveAddress( UCHAR addr, bool force = false );

并将其从基类的源文件中删除:

int CI2cHal::SetI2cSlaveAddress(UCHAR addr,布尔力)

然后编译器很高兴,所有代码都按预期工作(我可以向函数 SetI2cSlaveAddress() 提供一两个参数 >)!

因此,不仅对于类的用户来说,将参数的默认值放入头文件中很重要,而且对于编译和功能而言,这显然是必须的!

Although this is an "old" thread, I still would like to add the following to it:

I've experienced the next case:

  • In the header file of a class, I had
int SetI2cSlaveAddress( UCHAR addr, bool force );
  • In the source file of that class, I had
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
   ...
}

As one can see, I had put the default value of the parameter "force" in the class source file, not in the class header file.

Then I used that function in a derived class as follows (derived class inherited the base class in a public way):

SetI2cSlaveAddress( addr );

assuming it would take the "force" parameter as "false" 'for granted'.

However, the compiler (put in c++11 mode) complained and gave me the following compiler error:

/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
                 from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2

But when I added the default parameter in the header file of the base class:

int SetI2cSlaveAddress( UCHAR addr, bool force = false );

and removed it from the source file of the base class:

int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )

then the compiler was happy and all code worked as expected (I could give one or two parameters to the function SetI2cSlaveAddress())!

So, not only for the user of a class it's important to put the default value of a parameter in the header file, also compiling and functional wise it apparently seems to be a must!

各自安好 2024-10-24 01:35:26

还有一点我没有发现任何人提到:

如果你有虚拟方法,每个声明都可以有自己的默认值!

这取决于您调用的接口将使用哪个值。

ideone 上的示例

struct iface
{
    virtual void test(int a = 0) { std::cout << a; }
};

struct impl : public iface
{
    virtual void test(int a = 5) override { std::cout << a; }
};

int main()
{
    impl d;
    d.test();
    iface* a = &d;
    a->test();
}

它打印 50

我强烈建议您不要像这样使用它这

是因为在这两种情况下都会执行 impltest 函数,即使默认参数值是从 impl 中选取的> 在 d.test() 中,以及来自 a->test() 中的 iface。另请参阅下面 Gufino2 的评论。他指的是《Effective C++》的第 37 条。

One more point I haven't found anyone mentioned:

If you have virtual method, each declaration can have its own default value!

It depends on the interface you are calling which value will be used.

Example on ideone

struct iface
{
    virtual void test(int a = 0) { std::cout << a; }
};

struct impl : public iface
{
    virtual void test(int a = 5) override { std::cout << a; }
};

int main()
{
    impl d;
    d.test();
    iface* a = &d;
    a->test();
}

It prints 50

I strongly discourage you to use it like this

This is because it is impl's test function that executes in both cases even though the default argument value is picked from impl in d.test() and from iface in a->test(). Refer Gufino2's comment below, also. He is referring to Item 37 of Effective C++.

笨死的猪 2024-10-24 01:35:26

如果函数是公开的 - 非成员、公共或受保护 - 那么调用者应该知道它们,并且默认值必须位于标头中。

如果这些函数是私有的且不合规的,那么将默认值放入实现文件中确实有意义,因为这允许进行不会触发客户端重新编译的更改(对于在企业规模中共享的低级库来说,这有时是一个严重的问题)发展)。也就是说,这肯定可能会造成混乱,并且在标头中以更直观的方式呈现 API 具有文档价值,因此请选择您的妥协方案 - 尽管当没有任何令人信服的理由时,一致性是最重要的。

If the functions are exposed - non-member, public or protected - then the caller should know about them, and the default values must be in the header.

If the functions are private and out-of-line, then it does make sense to put the defaults in the implementation file because that allows changes that don't trigger client recompilation (a sometimes serious issue for low-level libraries shared in enterprise scale development). That said, it is definitely potentially confusing, and there is documentation value in presenting the API in a more intuitive way in the header, so pick your compromise - though consistency's the main thing when there's no compelling reason either way.

小姐丶请自重 2024-10-24 01:35:26

声明通常是最“有用”的,但这取决于您想要如何使用该类。

两者均无效。

the declaration is generally the most 'useful', but that depends on how you want to use the class.

both is not valid.

溺深海 2024-10-24 01:35:26

好问题...
我发现编码人员通常使用声明来声明默认值。根据编译器,我也被坚持一种方式(或警告)或另一种方式

void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
    using namespace std;
    cout << nVal1 << << nVal2 << endl;
}

Good question...
I find that coders typically use the declaration to declare defaults. I've been held to one way (or warned) or the other too based on the compiler

void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
    using namespace std;
    cout << nVal1 << << nVal2 << endl;
}
蝶舞 2024-10-24 01:35:26

您可以执行任一操作(根据标准),但请记住,如果您的代码在包含默认参数的定义之前看到没有默认参数的声明,则可能会出现编译错误。

例如,如果您包含包含没有默认参数列表的函数声明的标头,则编译器将查找该原型,因为它不知道您的默认参数值,因此原型将不匹配。

如果您在定义中放置带有默认参数的函数,则包含该文件,但我不建议这样做。

You may do in either (according to standard), but remember, if your code is seeing the declaration without default argument(s) before the definition that contains default argument, then compilation error can come.

For example, if you include header containing function declaration without default argument list, thus compiler will look for that prototype as it is unaware of your default argument values and hence prototype won't match.

If you are putting function with default argument in definition, then include that file but I won't suggest that.

颜漓半夏 2024-10-24 01:35:26

再补充一点。带有默认参数的函数声明应从右到左从上到下排序。

例如在下面的函数声明中,如果更改声明顺序,则编译器会给出缺少默认参数的错误。原因是编译器允许您在同一范围内将函数声明与默认参数分开,但它应该按从右到左(默认参数)和从上到下(函数声明默认参数的顺序)的顺序。

//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error 
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK

int main() {
    function("Using only one Default Argument", false, true);
    function("Using Two Default Arguments", false);
    function("Using Three Default Arguments");
    return 0;
}

//definition
void function(char const *msg, bool three, bool two, bool one ) {
    std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}

Adding one more point. Function declarations with default argument should be ordered from right to left and from top to bottom.

For example in the below function declaration if you change the declaration order then the compiler gives you a missing default parameter error. Reason the compiler allows you to separate the function declaration with default argument within the same scope but it should be in order from RIGHT to LEFT (default arguments) and from TOP to BOTTOM(order of function declaration default argument).

//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error 
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK

int main() {
    function("Using only one Default Argument", false, true);
    function("Using Two Default Arguments", false);
    function("Using Three Default Arguments");
    return 0;
}

//definition
void function(char const *msg, bool three, bool two, bool one ) {
    std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文