15

Visual C++ 2010 でスマート等価テスト マクロ型テンプレート関数を実装しようとしたときに、テンプレート関数の既定の引数に関する VS のバグに関係する問題に遭遇しました。パラメーターの値を追加の関数でラップして修正しましたが、関数を 1 行で 2 回使用できないことがわかりました。

ヘッダー ファイル:

// 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 のデバッグ ------
test.cpp
c:\users\ninja\documents\visual studio 2010\projects\test\test\test.cpp(24 ): エラー C2440: 'default argument' : 'const float *' から 'const float &'
に変換できません理由: 'const float *' から 'const float' に変換できません
この変換が可能なコンテキストがありません

問題のある行は、論理 AND を使用して smartEqual() を 2 回呼び出そうとした行です。

なぜこれが起こるのかわかりません。「eps」を参照型から単純な値型に変更すると修正されますが、何が起こっているのか知りたいです。

ありがとう!

4

3 に答える 3

13

あなたは今、このVS10のバグにぶつかったと思います。

コードはVS11ベータ版で正常にコンパイルされます。

次のように変更することで、デフォルト値(VS10の主要な問題のようです)を回避できる可能性があります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());
}


別のオプションは、値を渡すようにイプシロンパラメーターを変更することです。

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    T eps = epsilon<T>())
{
    return (v1 == v2);
}
于 2012-04-27T02:01:50.613 に答える
2

コードは VS2010 では失敗しましたが、Intel コンパイラでは問題ありません。VS2010のバグのようです

于 2012-04-27T02:15:31.370 に答える
2

いくつかの検討の後、@Fraser が提案したさらに別のソリューションを使用することにしました (ただし、彼からインスピレーションを得ました)。独自の回答を作成します。

  1. 最初の解決策では、eps のカスタム値を使用できるという柔軟性が失われます。
  2. 値渡しによる 2 番目の解決策は、特に将来、この関数をより工夫された型に使用することを決定した場合は、間違っているように感じます。

VS はパラメーターのデフォルト値に関するバグでオーバーライドされているように見えるので (テンプレートのみ?)、smartEqual の 2 つのバージョンを作成して問題を回避するのが最も賢明な方法のようです。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);
于 2012-04-27T03:21:18.677 に答える