2012-06-18 19 views
24

Birden çok aritmetik türüyle çalışan bir proje geliştiriyorum.Neden bazı işlevler <cmath> std ad alanında değil?

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); 
... 
} 

Beni rahatsız eden olduğunu bu gibi bir kod kullandığınızda:

yüzden bir kullanıcı tanımlı aritmetik türü için asgari gereklilikler tanımlanmaktadır kafayla, yapılan

error: call of overloaded 'sin(ArithmeticF&)' is ambiguous 
candidates are: 
double sin(double) 
const ArithmeticF arithmetic::sin(const ArithmeticF&) 
:
#include "user_defined_arithmetic.h" 

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

bir derleyici hatası alıyorum

Hiçbir zaman <math.h> başlığını kullanmamıştım, yalnızca <cmath>. Bir başlık dosyasında hiç using namespace std kullanmamıştım.

gcc 4.6 kullanıyorum. *. Ben belirsiz beyanı içeren başlık ne olduğunu kontrol ve olarak çıkıyor:

mathcalls.h: biliyorum

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

, <cmath><math.h> içerir, ama bu tarafından beyanları kalkan olmalıdır std ad alanı. Ben <cmath> başlığına içine kazmak ve bulmak:

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) 
{ 
... 

Yani Ad std#include <math.h> sonra başlar. Burada yanlış bir şey mi var, yoksa bir şeyi yanlış anlamış mıyım?

+2

Bazı şeylerde çalışmıyor Söylemeye gerek yok: aritmetik türlerini (ayrılmaz türleri + çift + şamandıra) kullanırken genellikle daha verimlidir (ve ortak) referansla değerden geçmek. Belirli bir sürümü istediğiniz bir işlevi çağırırken, ad alanı X 'kullanarak bir '' ekleme yerine, aramaya hak kazanın. Alternatif olarak * yönergesiyle * kullanabilirsiniz ('arithmetic :: sin' kullanarak). Sonunda, 'typedef' düzenleyerek değişen türlerin tüm yaklaşımı gerçekten kötü bir fikirdir. –

+0

@ DavidRodriguez-dribeas: Teşekkürler! Lütfen bana alternatif bir çözüm önerebilir misin? Ben referans ile geçiş kullanıyorum, çünkü sayı özel bir tip olabilir. Bu, hatta birkaç kilobayt büyük alabilirsiniz demektir. Fonksiyonları sıraladığımda ve std temel fonksiyonlarını satır içi içinde kullandığımda, hiçbir zarar vermeyeceğini umuyordum. Yoksa olacak mı? Bana biraz öneri verebilir misiniz lütfen? –

+0

@ DavidRodriguez-dribeas: C++ yaklaşımının soyut bir sınıf bildirmek olacağını biliyorum, ancak matris hesaplamaları için kullandığım bir kitaplık yerleşik bir tür kullandığınızda önemli optimizasyonlar kullanıyor. Ben sadece bu avantajı kaybetmek istemedim –

cevap

16

C++ standart kitaplığı uygulamalarının, global ad alanında ve ayrıca std'da C kitaplığı işlevleri bildirmesine izin verilir. Bazıları buna hata diyor, çünkü (bulunduğunuz gibi) isim alanı kirliliği kendi isimlerinizle çatışmaya neden olabilir. Ancak, bu şekilde, bu yüzden onunla yaşamalıyız. Adınızı arithmetic::sin olarak nitelendirmeniz yeterlidir. standart (C++ 11 17.6.1.2/4) sözleriyle

: Gerçekten, her zaman çizgisinde cmath etrafında biraz sarmalayıcı yazabilirsiniz istiyorsa

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

Derleyicinin ne kadar zekice olduğuna bağlı olarak ek işlev çağrısından bazı ek yükler olabileceğini varsayalım.

+0

Bu, bu sorunu tam olarak çözmez; ad alanı mylib { çift günah (çift x) { dönüş 1.0; Int ana() { \t namespace mylib; std :: cout << stdmath :: sin (1) << std :: endl; std :: cout << günah (1) << std :: endl; } 'hala" belirsiz bir çağrı hatası "alıyorsunuz. – alfC

+0

@alfC hayır yapmazsınız. Bu cevabın bütün noktası 'hpp' başlığı yerine' stdmath''nın 'cpp' dosyasında' ' içermesidir. – Ruslan

1

Bu, bu sorunu çözmeye başlamak için alçakgönüllü bir girişimdir. (Öneriler karşılandı.)

Uzun zamandır bu problemle uğraşıyorum.

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

Bu benim düşüncem sinir bozucu bir hata ya da en azından bir çok talihsiz bir durumdur içinde: Bir vaka sorunu çok açıktır Bu durumda idi.(En azından GCC'de ve Linux'ta GCC kütüphanesi olarak.)

Son zamanlarda bu soruna bir kez daha vurdum. cmath (GCC) 'ye bakarak başlığın sadece C-fonksiyonlarını aşırı yüklemesi ve isim-alanını süreç içinde sıkıştırması gibi görünüyor. Bunun Bununla

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

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

Bu #include<cmath> tam olarak eşdeğer değildir neredeyse eminim ama çoğu fonksiyonları çalışmıyor gibi görünüyor çalışır.

En kötüsü, sonunda bazı bağımlılık kitaplığının sonunda #inclulde<cmath> olacaktır. Bunun için henüz bir çözüm bulamadım.

NOT: yeniden gözden geçirmek isteyebilirsiniz bu her

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

"namespace std" öğesindeki herhangi bir şeyin bildirimi UB'dir. – Ruslan

İlgili konular