実際には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)はあいまいな関数呼び出しを報告します。 abs
をfabs
に変更すると、エラーはOSXで解決されますが、Linux clang、gcc、およびVisualStudioでも同じエラーが表示されるようになりました。
ファブを使用したVisualStudioでのエラー:
349 error C2668: 'fabs' : ambiguous call to overloaded function
[〜#〜] update [〜#〜]
この例はOSXシステムでコンパイルされていますが、ほぼ同一のプロジェクトではコンパイルされていません。解決策は<cstdlib>
別のヘッダーに戻るのではなく、ソースに明示的に。理由は不明ですが、xcode/clangがヘッダーインクルードに正しく従わないためと思われます。
問題はlibc++
は、 std :: abs in cmath :の積分オーバーロードに完全に準拠しているわけではありません。
double fabs( Integral arg ); (7) (since C++11)
cstdlib を含めると、ヘッダーに整数型専用のオーバーロードがあるため、問題が解決します。
参考までに、ドラフトC++ 11標準セクション26.8
[c.math]段落11
言う:
さらに、以下を保証するのに十分な追加の過負荷が存在するものとします。
次のアイテムが含まれています。
- それ以外の場合、doubleパラメーターに対応する引数の型がdouble型または整数型の場合、doubleパラメーターに対応するすべての引数は事実上doubleにキャストされます。
これは、次の理由で変更される可能性が非常に高い状況です LWGアクティブな問題2192:std :: abs(0u)の有効性と戻り値の型が不明です 。私は推測していますlibc++
この欠陥レポートで提起された問題のため、cmath
にオーバーロードを提供しないことを選択します。
詳細については、 std :: abs(0u)は不正な形式ですか? を参照してください。
解決策は、明示的に#include <cstdlib>
OS Xマシンでは、何らかの理由でVisual Studioが依存関係でそれを見つけて含めますが、clangはそうではありません。 XcodeまたはVisualStudioのいずれかで問題が発生する可能性があるため、プロジェクトに含まれる同様のインクルードチェーンを再現し、エラーを最小限の方法で再現しようとします。
この問題の原因となるテンプレート関数が多数ある場合は、次のドロップイン置換を使用できます。
#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
が必要です。)