9 Şubat 2018 Cuma

using Anahtar Kelimesi

using ve Namespace (İsim Alanı)
using kelimesi eskiden beri namespace'leri dahil etmek için kullanılır. namespace scope, yani isim etki alanı şöyledir. A'yı dahil eden her bir B translation unit', A'nın değişken, metod ve sınıflarına erişebilir.
namespace A {  \
  int i = 9;      | <-- namespace A scope. 
}              /

namespace B {      \
  using namespace A;  | <-- namespace B scope. "i" is visible after 
  void bar()          |     the "using namespace" line.
  {                   |
    i += 1; /*Ok*/  |     
  }                   |
}                  /

namespace B {     \
  void foo()         |
  {                  | <-- still namespace B scope. "i" is still visible
    i += 1; /*Ok*/ |
  }                  |
}    
using ::std:: veya using ::mynamespace
Bazen kodlarda namespace'ten önce :: karakterini görebiliriz. Yani kod şuna benzeyebilir.
using std::...;
veya
using ::std::...;
Bu kullanım şekli farklı namespace'ler içindeki sınıf isimlerinin çakışması yüzünden oluyor. Eğer using ::std yaparsak en tepedeki namespace içindeki bir şeyi kullanmak istediğimizi belirtiriz. Tabiki std içindeki sınıfları kullanmamak gerekir. Dolayısıyla kendi kodlarımızda da çakışma olabileceğini düşünerek şöyle bir örnek verebiliriz.
namespace A
{
    namespace B
    {
         class C;
    }
}
namespace B
{ 
    class C;
}
namespace A
{
    using B::C; // resolves to A::B::C
    using ::B::C; // resolves to B::C
    // (note that one of those using declarations has to be
    // commented for making this valid code!)
}
using ve Ata Sınıf - c++11
Ata sınıfta normalde erişemediğimiz metodlara erişebilmemizi sağlar. Bu yöntem aynı zamanda Inheriting Constructor için de kullanılır. Bu konu için C++11 ile Constructor Inheritance yazısına bakınız.

Örnek
Şöyle yaparız.
struct Base
{
  int foo(int);
  int foo(int, int);
};

struct Child : Base
{
  using Base::foo; //Her iki foo metodu erişilir hale gelir
  int foo(int, int, int);
};
Kullanmak için şöyle yaparız.
Child c;
c.Base::foo(0, 0);
Eğer bir overload metodu tekrar erişilemez yapmak istersek şöyle yaparız.
struct Base
{
  int foo(int);
  int foo(int, int);
};

struct Child : Base
{
  using Base::foo;
  int foo(int, int) = delete;
  int foo(int, int, int);
};
using ve typdef - c++11
using anahtar kelimesi typedef olarak kullanılabilir. Açıklaması şöyle.
A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. Such a typedef-name has the same semantics as if it were introduced by the typedef specifier.
Söz dizimi şöyle.
using <typedef-name> = <type>;
Şununla aynı şeydir.
typedef <type> <typedef-name>;
Örnek
unnamed struct için şöyle yaparız.
using S = struct { int x; }
using Tip Uyumluluğu - c++11
using aynı typedef gibi kullanılabiliyor ve dolayısıyla typdef uyumluluğunda karşımıza çıkan problemin aynısı burada da  görülebilir.
Örnek
Şöyle yaparız.
using PortalId = std::string;
using CakeId   = std::string;

PortalId portal_id("2");
CakeId cake_id("is a lie");

portal_id = cake_id; // OK
Çözümlerden bir tanesi kalıtım ile farklı bir sınıf tanımlamak. Ben bu yöntemi sevmiyorum. Şöyle bir macro tanımlarız.
#define SAFE_TYPEDEF(Base, name) \
class name : public Base { \
public: \
    template <class... Args> \
    explicit name (Args... args) : Base(args...) {} \
    const Base& raw() const { return *this; } \
};
Daha sonra farklı sınıflar elde ettiğimiz için derleyici bizim için karışıklıkları yakalar.
SAFE_TYPEDEF(std::string, PortalId);
SAFE_TYPEDEF(std::string, CakeId);

int main()
{
    PortalId portal_id("2");
    CakeId cake_id("is a lie");
    std::map<CakeId, PortalId> p_to_cake; // OK

    p_to_cake[cake_id]   = portal_id; // OK
    p_to_cake[portal_id] = cake_id;   // COMPILER ERROR

    portal_id = cake_id;        // COMPILER ERROR
    portal_id = "1.0";          // COMPILER ERROR
    portal_id = PortalId("42"); // OK
    return 0;

}
İkinci yöntem ise farklı tag'ler ile template tanımlamak. Şöyle bir template ve tagler tanımlarız.
#include <iostream>
#include <string>
#include <map>

// define some tags to create uniqueness 
struct portal_tag {};
struct cake_tag {};

// a string-like identifier that is typed on a tag type   
template<class Tag>
struct string_id
{
    // needs to be default-constuctable because of use in map[] below
    string_id(std::string s) : _value(std::move(s)) {}
    string_id() : _value() {}

    // provide access to the underlying string value        
    const std::string& value() const { return _value; }
private:
    std::string _value;

    // will only compare against same type of id.
    friend bool operator < (const string_id& l, const string_id& r) {
        return l._value < r._value;
    }
};
Daha sonra farklı tag'ler kullandığımız için derleyici bizim için karışıklıkları yakalar.
// create some type aliases for ease of use    
using PortalId = string_id<portal_tag>;
using CakeId = string_id<cake_tag>;

using namespace std;

// confirm that requirements are met
auto main() -> int
{
    PortalId portal_id("2");
    CakeId cake_id("is a lie");
    std::map<CakeId, PortalId> p_to_cake; // OK

    p_to_cake[cake_id]   = portal_id; // OK
//    p_to_cake[portal_id] = cake_id;   // COMPILER ERROR

//    portal_id = cake_id;        // COMPILER ERROR
//    portal_id = "1.0";          // COMPILER ERROR
    portal_id = PortalId("42"); // OK
    return 0;
}






Hiç yorum yok:

Yorum Gönder