28

複数の算術型で動作するプロジェクトを開発しています。そこで、ユーザー定義の算術型の最小要件が定義されているヘッダーを作成しました。

user_defined_arithmetic.h :

typedef double ArithmeticF;   // The user chooses what type he 
                              // wants to use to represent a real number

namespace arithmetic          // and defines the functions related to that type
{

const ArithmeticF sin(const ArithmeticF& x);
const ArithmeticF cos(const ArithmeticF& x);
const ArithmeticF tan(const ArithmeticF& x);
...
}

私を悩ませているのは、次のようなコードを使用するときです。

#include "user_defined_arithmetic.h"

void some_function()
{
    using namespace arithmetic;
    ArithmeticF lala(3);
    sin(lala);
}

コンパイラ エラーが発生します。

error: call of overloaded 'sin(ArithmeticF&)' is ambiguous
candidates are:
double sin(double)
const ArithmeticF arithmetic::sin(const ArithmeticF&)

<math.h>ヘッダーのみを使用したことはありません<cmath>using namespace stdヘッダー ファイルで を使用したことはありません。

gcc 4.6.* を使用しています。あいまいな宣言を含むヘッダーを確認したところ、次のようになりました。

mathcalls.h :

Prototype declarations for math functions; helper file for <math.h>.
...

<cmath>が含まれていることはわかっています<math.h>が、 std 名前空間による宣言を保護する必要があります。<cmath>ヘッダーを掘り下げて見つけました:

cmath.h :

...

#include <math.h>

...

// Get rid of those macros defined in <math.h> in lieu of real functions.
#undef abs
#undef div
#undef acos
...

namespace std _GLIBCXX_VISIBILITY(default)
{
...

したがって、名前空間 stdは#include <math.h>. ここに何か問題がありますか、それとも私は何かを誤解しましたか?

4

3 に答える 3

25

C++ 標準ライブラリの実装では、C ライブラリ関数をグローバル名前空間および で宣言することが許可されていますstd。(お気づきのように) 名前空間の汚染が自分の名前と競合する可能性があるため、これを間違いと呼ぶ人もいます。しかし、それが現状なので、私たちはそれと一緒に生きなければなりません。名前を として修飾する必要がありますarithmetic::sin

標準の言葉で (C++11 17.6.1.2/4):

ただし、C++ 標準ライブラリでは、宣言 (C でマクロとして定義されている名前を除く) は、名前空間の名前空間スコープ (3.3.6) 内にありますstdこれらの名前が最初にグローバル名前空間スコープ内で宣言され、次に明示的な using 宣言 (7.3.3) によって名前空間 std に注入されるかどうかは指定されていません。

于 2012-06-18T15:32:56.737 に答える
3

本当に必要な場合は、次cmathの行に沿って、いつでも小さなラッパーを書くことができます。

//stdmath.cpp
#include <cmath>
namespace stdmath
{
    double sin(double x)
    {
        return std::sin(x);
    }
}

//stdmath.hpp
#ifndef STDMATH_HPP
#define STDMATH_HPP
namespace stdmath {
    double sin(double);
}
#endif

//uses_stdmath.cpp
#include <iostream>
#include "stdmath.hpp"

double sin(double x)
{
    return 1.0;
}

int main()
{
    std::cout << stdmath::sin(1) << std::endl;
    std::cout << sin(1) << std::endl;
}

コンパイラーの巧妙さによっては、追加の関数呼び出しによるオーバーヘッドが発生する可能性があると思います。

于 2012-10-09T17:52:00.770 に答える
1

これは、この問題を解決するためのささやかな試みです。(提案は大歓迎です。)

私はこの問題に長い間取り組んできました。問題が非常に明白な場合は、次の場合です。

#include<cmath>
#include<iostream>

namespace mylib{
    std::string exp(double x){return "mylib::exp";}
}

int main(){
    std::cout << std::exp(1.) << std::endl; // works
    std::cout << mylib::exp(1.) << std::endl; // works

    using namespace mylib;
    std::cout << exp(1.) << std::endl; //doesn't works!, "ambiguous" call
    return 0;
}

私の意見では、これは厄介なバグであるか、少なくとも非常に不幸な状況です。(少なくとも GCC では、Linux では GCC ライブラリを使用する clang で。)

最近、私はその問題にもう一度挑戦しました。(GCC の)を見るcmathと、ヘッダーは単に C 関数をオーバーロードし、その過程で名前空間を台無しにしているように見えます。

namespace std{
   #include<math.h>
}
//instead of #include<cmath>

それとこれは動作します

using namespace mylib;
std::cout << exp(1.) << std::endl; //now works.

これが完全に同等ではないことはほぼ確実です#include<cmath>が、ほとんどの機能は機能しているようです。

最悪なのは、最終的に一部の依存ライブラリが最終的に#inclulde<cmath>. そのため、まだ解決策を見つけることができませんでした。

:言うまでもなく、これはまったく機能しません

namespace std{
   #include<cmath> // compile errors
}
于 2014-08-13T05:20:46.057 に答える