2015-08-25 46 views
24

請考慮下面的代碼:當內聯名稱空間存在時,如何顯式引用封閉名稱空間?

#include <iostream> 

namespace Foo{ 

    void ool() // Version A 
    { 
     std::cout << "Foo::ool" << std::endl; 
    } 

    inline namespace Bar{ 
     void ool() // Version B 
     { 
      std::cout << "Foo::Bar::ool" << std::endl; 
     } 
    } 
} 


int main() 
{ 
    Foo::ool(); // <- error 
} 

兩個鏘和G ++正確標註Foo::ool模棱兩可。我可以毫無問題地致電Foo::Bar::ool,但有沒有辦法在不更改聲明的情況下調用版本A?

我發現人們在類似的位置試圖瞭解發生了什麼,但我沒有看到這種情況下的解決方案。

我在這種情況下,因爲我有一個項目,其中包括std::__1::pairstd::pair的聲明,在不同的地方做出,std::__1是一個內聯命名空間。我需要明確指出std::pair的代碼。有沒有解決方案?

+1

引入__1 ::對,是指對std :: pair之前或許定義一個別名模板? – Columbo

+3

你確定你沒有看[這個問題](http://stackoverflow.com/questions/9000816/libc-stop-std-renaming-to-std-1)? (基本上,解決方案是在編譯選項中添加-std = C++ 0x(或類似於新編譯器)。)您使用的編譯器版本和設置是什麼? – utnapistim

+0

utnapistim:你是對的。我遇到了這個解決方案,但是它讓我很好奇在一般情況下如何解決這個特定的歧義。我認爲這個解決方案在std = libstdC++中更多地介紹了我的情況,但它確實解決了我的編譯問題,謝謝! – YvesQuemener

回答

12

我不認爲這是可能的;從cppreference

合格的名稱查找該檢查封閉命名空間將包括內嵌的命名空間的名稱,即使相同的名字出現在封閉命名空間。

但是,看起來你實際上並不處於你描述的情況,因爲你說這兩個定義是從不同的文件中提取的。因此,你「書籤」,以便在更多的外部定義能夠調用它,當你需要它:

#include <iostream> 

// Equivalent of first include 
namespace Foo{ 
    void ool() // Version A 
    { 
     std::cout << "Foo::ool" << std::endl; 
    } 
} 

const auto& foo_ool = Foo::ool; 

// Equivalent of second include 
namespace Foo{ 
    inline namespace Bar{ 
     void ool() // Version B 
     { 
      std::cout << "Foo::Bar::ool" << std::endl; 
     } 
    } 
} 

int main() 
{ 
    foo_ool(); // Works 
} 

如果你想收藏的東西是一個類型,一個簡單的using指令就足夠了。爲您的等效代碼看起來像:

#include <my_first_include> 

// bookmark code 

#include <my_second_include> 

// rest of the code 
+0

謝謝。我覺得很奇怪,編譯器會默認接受一個新的內聯定義的類。封閉名稱空間中的Foo :: ool函數完全無法實現。在我看來,這種行爲至少應該引發一個警告。 但謝謝你的書籤竅門。這是最接近這個問題的解決方案。 – YvesQuemener

2

我不認爲你可以引用ool含糊不清當一個內聯命名空間確實有一個同名的方法ool

但你可以試試這個;

#include <iostream> 

namespace Foo{ 

    inline namespace A { 
     void ool() // Version A 
     { 
      std::cout << "Foo::ool" << std::endl; 
     } 
    } 

    namespace Bar{ 
     void ool() // Version B 
     { 
      std::cout << "Foo::Bar::ool" << std::endl; 
     } 
    } 
} 


int main() 
{ 
    Foo::ool(); // no error 
} 
  1. 總結方法namespace Foonamespace A然後inlinenamespace A
  2. Bar刪除內聯。

現在,如果您撥打一個電話Foo::ool();它會調用inline A::ool()
Bar::ool可以通過Foo::Bar::ool

5

你不能明確地指在封閉空間中定義的符號一旦內嵌命名空間已經看到被調用。

特別是對於您的情況,main中的合格查找被正確標記爲不明確(正如您自己所說的那樣)。查看cppreference最後一點:

合格的名稱查找該檢查封閉命名空間將包括內嵌的命名空間的名稱,即使相同的名字出現在封閉命名空間。


然而,還有其他的評論中指出,你可能面臨着配置的問題,在你的工具鏈調用當您嘗試使用std::pair

要解決你的問題,你需要確保調用編譯器來編譯C++代碼11,這將是與標誌:根據您的鐺/ GCC

版本

-std=c++11-std=c++0x

給出進一步的上下文:
內聯命名空間是一個C++ 11功能,主要用於在庫中允許符號版本。然後,C++標準庫實現可以在嵌套命名空間(使用非標準名稱)中定義不同版本的符號,並且根據編譯時請求的庫版本,工具鏈將嵌套命名空間中的一個定義爲內聯。看來你使用的是C++ 11版本的庫(因爲它定義了一些符號,特別是內聯名字空間_1中的pair),因此實際上在內聯名字空間中具有符號。

+0

是的,我真的用這種方式解決了我目前的問題,但我想知道如何以更通用的方式解決它。無論如何,謝謝你指出這些。 – YvesQuemener

+1

@YvesQuemener在語義上,您不需要到達* enclosing *符號:如果您實際上在同一個名稱空間中定義了幾次相同的符號(模重載)(直接寫入,通過使用聲明或通過內聯命名空間編寫) ,問題是多重聲明本身,而不是如何解決它們:) –

+0

是的,但是如果問題在於符號被重載的事實,爲什麼編譯器在它發生時不會提醒它?畢竟,它在同一範圍內發生重複定義的錯誤。 – YvesQuemener

相關問題