2012-06-18 2 views
24

私は複数の算術型で動作するプロジェクトを開発しています。<cmath>の一部の機能がstdネームスペースにないのはなぜですか?

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&) 

私はヘッダーを使用したことがなく、<cmath>のみを使用しました。私はusing namespace stdをヘッダファイルに使用していません。

gcc 4.6。*を使用しています。私はあいまいな宣言を含むヘッダが何であるかをチェックし、それがあることが判明:私は<cmath><math.h>が含まれていることを、知っているが、それはで宣言を保護する必要があります

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

mathcalls.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>を開始します。ここに何か間違っているのですか、何かを誤解しましたか?

+2

いくつかの点では動作しません。言うまでもなく:算術型(整数型+ダブル+フロート)を使用している場合、それは通常、より効率的です(共通)を参照渡しよりも値渡しすることができます。特定のバージョンが必要な関数を呼び出すときは、 'using namespace X'を追加するのではなく、呼び出しを修飾します。あるいは、* usingディレクティブ*( 'using arithmetic :: sin')を使用することもできます。最後に、 'typedef'を編集して型を変更するというアプローチは、本当に悪い考えです。 –

+0

@ DavidRodriguez-dribeas:ありがとう!どうか、私に別の解決策を教えてもらえますか?番号はカスタムタイプにすることができるので、私は参照渡しを使用しています。つまり、それは数キロバイトも大きくなる可能性があります。私は関数をインライン化し、インラインの中でstdの基本関数を使用すると害は起こらないことを期待していました。それとも?私にいくつかの提案をお願いしますか? –

+0

@DavidRodriguez-dribeas:C++のアプローチは抽象クラスを宣言することですが、行列計算に使用するライブラリは、組み込み型を使用するとかなりの最適化を使用します。私はちょうどこの利点を失いたくはありませんでした –

答えて

16

C++標準ライブラリの実装では、Cライブラリ関数をグローバル名前空間で宣言することも、stdで宣言することもできます。名前空間の汚染があなた自身の名前と競合する可能性があるので(あなたが見つけたように)、これは間違いです。しかし、それはそれである方法なので、私たちはそれと共に生きなければなりません。あなたの名前はarithmetic::sinに限定されています。標準(C++ 11 17.6.1.2/4)の言葉で

:あなたは本当に、あなたはいつもの線に沿って、cmathの周りに少しラッパーを書くことができますしたい場合は

In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std . It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).

3

//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; 
} 

コンパイラがどれほど巧妙であるかに応じて、追加の関数呼び出しからいくらかのオーバーヘッドが発生する可能性があります。

+0

これは完全に問題を解決するものではなく、 'namespace mylib { double sin(double x) { return 1.0; } } int main() { \t using namespace mylib; std :: cout << stdmath :: sin(1)<< std :: endl; std :: cout << sin(1)<< std :: endl; } 'まだあいまいな呼び出しエラーが発生します。 – alfC

+0

@alfCいいえ、あなたはしません。この回答の要点は、 'hpp'ヘッダの代わりに' stdmath'の 'cpp'ファイルに' 'を入れることです。 – Ruslan

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ライブラリを使用しています)

最近、私はもう一つの問題を打ちました。 cmath(GCCの)を見てみると、ヘッダーは単純にCの関数をオーバーロードし、プロセス内の名前空間をねじ込むだけのようです。それによって

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

これは、私は、これは#include<cmath>とまったく同じではないことはほぼ確信しているが、ほとんどの機能が動作するようには思え

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

に動作します。

最悪の場合、最終的にいくつかの依存ライブラリは最終的に#inclulde<cmath>になります。そのために私はまだ解決策を見つけることができませんでした。

:あなたは再考したい場合があり、これはすべての

namespace std{ 
    #include<cmath> // compile errors 
} 
+2

'namespace std'の宣言はUBです。 – Ruslan

関連する問題