web-dev-qa-db-ja.com

腹筋へのあいまいな呼び出し

実際にはfloatまたはdoubleのいずれかであるカスタムデータ型があります。 OSXを除くすべてのOSで、次のC++ 11テンプレートを正常にビルドできます。

#include <cmath>
#include <cstdlib>
#include <cstdint>

template< class REAL_T >
inline REAL_T inhouse_abs(REAL_T i_val)
{
    return std::abs((REAL_T)i_val);
}

int main()
{
    int32_t ui = 2;
    inhouse_abs(ui);
    return 0;
}

ただし、clang 6.0(3.5 LLVM)はあいまいな関数呼び出しを報告します。 absfabsに変更すると、エラーはOSXで解決されますが、Linux clang、gcc、およびVisualStudioでも同じエラーが表示されるようになりました。

ファブを使用したVisualStudioでのエラー:

349 error C2668: 'fabs' : ambiguous call to overloaded function

[〜#〜] update [〜#〜]

この例はOSXシステムでコンパイルされていますが、ほぼ同一のプロジェクトではコンパイルされていません。解決策は<cstdlib>別のヘッダーに戻るのではなく、ソースに明示的に。理由は不明ですが、xcode/clangがヘッダーインクルードに正しく従わないためと思われます。

10
EntangledLoops

問題はlibc++は、 std :: abs in cmath :の積分オーバーロードに完全に準拠しているわけではありません。

double      fabs( Integral arg ); (7)   (since C++11)

cstdlib を含めると、ヘッダーに整数型専用のオーバーロードがあるため、問題が解決します。

参考までに、ドラフトC++ 11標準セクション26.8[c.math]段落11言う:

さらに、以下を保証するのに十分な追加の過負荷が存在するものとします。

次のアイテムが含まれています。

  1. それ以外の場合、doubleパラメーターに対応する引数の型がdouble型または整数型の場合、doubleパラメーターに対応するすべての引数は事実上doubleにキャストされます。

これは、次の理由で変更される可能性が非常に高い状況です LWGアクティブな問題2192:std :: abs(0u)の有効性と戻り値の型が不明です 。私は推測していますlibc++この欠陥レポートで提起された問題のため、cmathにオーバーロードを提供しないことを選択します。

詳細については、 std :: abs(0u)は不正な形式ですか? を参照してください。

10
Shafik Yaghmour

解決策は、明示的に#include <cstdlib> OS Xマシンでは、何らかの理由でVisual Studioが依存関係でそれを見つけて含めますが、clangはそうではありません。 XcodeまたはVisualStudioのいずれかで問題が発生する可能性があるため、プロジェクトに含まれる同様のインクルードチェーンを再現し、エラーを最小限の方法で再現しようとします。

4
EntangledLoops

この問題の原因となるテンプレート関数が多数ある場合は、次のドロップイン置換を使用できます。

#include <cmath>
#include <cstdlib>
#include <type_traits>

namespace util {


template <class T>
auto abs(T value) -> std::enable_if_t<std::is_unsigned<T>::value,
                                      T> { return value; }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_floating_point<T>::value,
                                      T> { return std::fabs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, int>::value,
                                      T> { return std::abs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, long>::value,
                                      T> { return std::labs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, long long>::value,
                                      T> { return std::llabs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_signed<T>::value &&
                                          !std::is_floating_point<T>::value &&
                                          !std::is_same<T, int>::value &&
                                          !std::is_same<T, long>::value &&
                                          !std::is_same<T, long long>::value,
                                      T> { return std::abs(value); }


} // namespace util

std::abs呼び出しをutil::absに置き換えるだけです。 (c++11が必要です。)

0
jan.sende