【问题标题】:Why does using this C++ function twice in one line cause a compile error?为什么在一行中使用此 C++ 函数两次会导致编译错误?
【发布时间】:2012-05-07 19:04:47
【问题描述】:

我在尝试在 Visual C++ 2010 中实现与 bug in VS in regard to default arguments of template functions 相关的智能相等测试宏类型模板函数时遇到了一些麻烦。我通过将参数的值包装在一个额外的函数中来修复它,但现在我发现我不能在一行中使用该函数两次!

头文件:

// example.h
#pragma once

#include <limits>

namespace myspace
{

// Need to define this separately to avoid a Visual Studio bug
template<typename T> T epsilon() { return std::numeric_limits<T>::epsilon(); }

// A generic equality test
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    const T &eps = epsilon<T>())
{
    return (v1 == v2);
}

// Template specialization for floating-point numbers
template<> bool smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps);

} // namespace myspace

源文件:

// example.cpp
#include "example.h"

using namespace std;
using namespace myspace;

// equal-macro specialization for floats using epsilon
template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps)
{
    return (fabs(v1 - v2) < eps);
}

int _tmain(int argc, _TCHAR* argv[])
{
    float a,b;
    bool x = smartEqual(a,b); // works ok
    bool x = smartEqual(a,b) && smartEqual(b,a); // error
    return 0;
}

报错如下:

----- 构建开始:项目:测试,配置:调试 Win32 ------
测试.cpp
c:\users\ninja\documents\visual studio 2010\projects\test\test\test.cpp(24):错误 C2440:“默认参数”:无法从“const float *”转换为“const float &”
原因:无法从 'const float *' 转换为 'const float'
没有可以进行这种转换的上下文

违规行是我尝试使用逻辑 AND 调用 smartEqual() 两次的行。

我不明白为什么会这样。将“eps”从引用类型更改为简单的值类型可以修复它,但我希望我知道发生了什么。

谢谢!

【问题讨论】:

  • 如果你用 2 个 不同的 类型实例化 smartEqual&lt;&gt;() 2 次,会不会留下 2 个版本的 epsilon(),它们只在返回类型上有所不同?跨度>
  • @Pavel:这确实也是一个有趣的问题,但作为 int ei = epsilon();浮点 ef = epsilon();编译好,似乎它们是某种独立的函数。我的意思是,编译器以某种方式区分它们。不知道如何。

标签: c++ visual-studio type-conversion default-arguments


【解决方案1】:

我想你现在已经点击了this VS10 bug

您的代码在 VS11 Beta 上编译正常。

您可以通过将smartEqual 更改为:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2)
{
    return (v1 == v2);
}

并且像这样专门针对浮点(和双精度):

template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2)
{
    return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon());
}


另一种选择是将epsilon参数更改为按值传递:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    T eps = epsilon<T>())
{
    return (v1 == v2);
}

【讨论】:

  • 抱住我,我着火了!我不寒而栗地想到在这一天结束之前我可能会解开哪些其他错误。 ;)
  • @neuviemeporte MS 应该雇佣你在 VS 发布之前测试它。
  • @neuviemeporte,别忘了这个小宝石:template&lt;typename T&gt; class A { class B : public C; };
  • 说真的,如果我不愿意升级到 VS 的 beta 版本,是否知道如何以正确的方式解决/解决这个问题?
  • 我会避免使用smartEqual 中的默认值。
【解决方案2】:

代码在 VS2010 中失败,但在 Intel 编译器中正常。看起来像 VS2010 中的一个错误

【讨论】:

    【解决方案3】:

    经过一番考虑,我决定采用@Fraser 建议的另一个解决方案(尽管我从他那里得到了灵感)并写下我自己的答案:

    1. 第一个解决方案剥夺了我使用自定义值 eps 的灵活性。
    2. 使用按值传递的第二个解决方案感觉不对,特别是如果将来我决定将此函数用于一些更人为的类型。

    由于 VS 似乎在参数的默认值方面被错误覆盖(仅在模板中?),似乎最明智的做法是通过创建两个版本的 smartEqual 来回避这个问题;有和没有 eps(使用默认值),它几乎做同样的事情,如果不是那么简洁:

    // An equality test that doesn't require the value of eps, default will be used
    template<typename T> inline bool smartEqual(
        const T &v1, 
        const T &v2)
    {
        return (v1 == v2);
    }
    
    // Float specialization: return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon());
    template<> inline bool smartEqual<float>(
        const float &v1, 
        const float &v2);
    
    // A custom-eps value equality test
    template<typename T> inline bool smartEqual(
        const T &v1, 
        const T &v2, 
        const T &eps)
    {
        return (v1 == v2);
    }
    
    // Float specialization: return (fabs(v1 - v2) < eps);
    template<> bool smartEqual<float>(
        const float &v1, 
        const float &v2, 
        const float &eps);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-18
      • 1970-01-01
      • 2011-06-09
      • 1970-01-01
      • 2022-06-15
      相关资源
      最近更新 更多