nested namespaces linking
От: Andrew S Россия http://alchemy-lab.com
Дата: 11.08.09 20:40
Оценка:
Всем привет.
Есть следующий код:

// настройка связей, в конфиге, в зависимости от платформы.
namespace fw
{
  namespace win
  {
  }
  using namespace win;
}

// реализация
namespace fw
{
  namespace win
  {
    namespace io
    {
      struct io_impl
      {
      };
    }
  }
}

// то, что видит пользователь

namespace fw
{
  namespace io
  {
    // using namespace fw::win::io
    struct io_front: io_impl // ошибка компиляции
    {
    };
  }
}

Для чего это нужно — есть кроссплатформенный фреймворк, реализация для каждой платформы располагается в неймспейсе этой платформы. В зависимости от опций компиляции "морда" собирает это дело при помощи using директив в неймспейс интерфейса фремворка. Сейчас, кроме настройки, которая происходит автоматически, если есть вложенные "ниже" неймспейсы, приходится делать дополнительный using в интерфейсе с пользователем. Не сложно, но и не камильфо.

Что хочется.
1. Понять причину ошибки компиляции, в смысле, где в стандарте посмотреть (3.4.6 и 7.3 просмотрел, вроде ничего похожего).
1 Добиться эффекта, чтобы fw::io мержилось с fw::io(from win) без дополнительного using.
2. Возможно, есть способ как то порефакторить это, дабы избежать подобных или других проблем. Например, есть мысли неймспейсы реализации расположить в другом порядке: fw::io::win. Как в этом случае обеспечить автоматические линки неймспейсов, не очень понятно (делать include внутри неймспейсов как то некошерно, хотя в данном случае... не знаю, в общем, не по фен шую).

Всем спасибо!
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: nested namespaces linking
От: Vamp Россия  
Дата: 11.08.09 21:10
Оценка:
AS>// реализация
AS>namespace fw
AS>{
AS> namespace win
AS> {
AS> namespace io
AS> {
AS> struct io_impl
AS> {
AS> };
AS> }
AS> }
AS>}

AS>// то, что видит пользователь


AS>namespace fw

AS>{
AS> namespace io
AS> {
AS> // using namespace fw::win::io
AS> struct io_front: io_impl // ошибка компиляции
AS> {
AS> };
AS> }
AS>}
AS>[/ccode]
Если я правильно понял (в чем я не до конца уверен), то есть два файла. В одном прописаны три пространства имен — fw, внутри которого win, и внутри которого io. Есть второй файл, в котором внутри fw прописан io. В таком случае ничего удивительного, что io_front из fw:win:io не виден в fw:io — это же совершенно другой неймспейс. Было бы как раз очень неправильно, если бы он был виден!

AS>1. Понять причину ошибки компиляции, в смысле, где в стандарте посмотреть (3.4.6 и 7.3 просмотрел, вроде ничего похожего).

Надеюсь, на этот вопрос я ответил.

AS>1 Добиться эффекта, чтобы fw::io мержилось с fw::io(from win) без дополнительного using.

Невозможно, если я все правильно понял.

AS>2. Возможно, есть способ как то порефакторить это, дабы избежать подобных или других проблем.

А почему не классическое решение?
class io {...};
clas win_io : io {...};
class nix_io : io {...};

class user_io : win_io

Или я чего-то кардинально недопонял?
Да здравствует мыло душистое и веревка пушистая.
Re: nested namespaces linking
От: Erop Россия  
Дата: 11.08.09 21:14
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>неймспейсы реализации расположить в другом порядке: fw::io::win. Как в этом случае обеспечить автоматические линки неймспейсов, не очень понятно (делать include внутри неймспейсов как то некошерно, хотя в данном случае... не знаю, в общем, не по фен шую).


Можно делать namespace io_win, например, или ещё какой. А потом задавать для него другое имя что-то типа:
namespace my {
    namespace win {
        namespace io {
            // тут реализация
        }
    }

    namespace io = win::io;
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: nested namespaces linking
От: Andrew S Россия http://alchemy-lab.com
Дата: 11.08.09 22:24
Оценка:
V>Если я правильно понял (в чем я не до конца уверен), то есть два файла. В одном прописаны три пространства имен — fw, внутри которого win, и внутри которого io. Есть второй файл, в котором внутри fw прописан io. В таком случае ничего удивительного, что io_front из fw:win:io не виден в fw:io — это же совершенно другой неймспейс. Было бы как раз очень неправильно, если бы он был виден!

Не так.

Выше мы настроили, что все, что из win попадает в fw. Почему то для сущностей в win, получается, это работает.
Более того, если мы закомментим то, что видит пользователь, то вполне сможем использовать fw::io::io_impl. Т.е. с точки зрения меня, как клиента неймспейса fw, получается два (!!!!) вложенных в него неймспейса io, причем разных. Один это внесенный в область видимости из win, а второй нативный. Аргументы "за" такое поведение при лукапе я тоже могу привести, но тем не менее, в данном случае ситуация не очень логична.

AS>>1. Понять причину ошибки компиляции, в смысле, где в стандарте посмотреть (3.4.6 и 7.3 просмотрел, вроде ничего похожего).

V>Надеюсь, на этот вопрос я ответил.

Никоим образом.

AS>>1 Добиться эффекта, чтобы fw::io мержилось с fw::io(from win) без дополнительного using.

V>Невозможно, если я все правильно понял.

AS>>2. Возможно, есть способ как то порефакторить это, дабы избежать подобных или других проблем.

V>А почему не классическое решение?
V>class io {...};
V>clas win_io : io {...};
V>class nix_io : io {...};

V>class user_io : win_io


V>Или я чего-то кардинально недопонял?


Видимо, да. Все наоборот. Есть реализации (в неймспейсах платформы), и их наследует или использует конечный класс, который и будет пользовать клиент.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: nested namespaces linking
От: Andrew S Россия http://alchemy-lab.com
Дата: 11.08.09 22:31
Оценка:
AS>>неймспейсы реализации расположить в другом порядке: fw::io::win. Как в этом случае обеспечить автоматические линки неймспейсов, не очень понятно (делать include внутри неймспейсов как то некошерно, хотя в данном случае... не знаю, в общем, не по фен шую).

E>Можно делать namespace io_win, например, или ещё какой. А потом задавать для него другое имя что-то типа:

E>
namespace my {
E>    namespace win {
E>        namespace io {
E>            // тут реализация
E>        }
E>    }

E>    namespace io = win::io;
E>}


Не уверен, что я понял мысль. Зачем нам делать это? В чем поинт? Как это использовать для достижения указанной цели (авто инжекта неймспейса в зависимости от конфига)? То, что есть io, я на этапе конфига не знаю — разработчик фреймворка может реализации в неймспейсных кластерах определять, если считает нужным.. io просто в качестве примера иллюстрации проблемы .

Повторюсь. В той схеме, что привел я — не нужно вообще ничего линковать _явно_, правила линка неймспейсов определяются в конфигурации, тот, кто пишет реализации, даже про них не знает. Если не пользует дополнительных неймспейсов Вот это, собственно, и надо как-то раскрутить. Один вариант решения этой проблемы я знаю, и написал о нем — меня он не устраивает.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: nested namespaces linking
От: Юрий Жмеренецкий ICQ 380412032
Дата: 11.08.09 22:42
Оценка: 12 (1) +2
Здравствуйте, Andrew S, Вы писали:

AS>Всем привет.

AS>Есть следующий код:

AS>
AS>// настройка связей, в конфиге, в зависимости от платформы.
AS>namespace fw
AS>{
AS>  namespace win
AS>  {
AS>  }
AS>  using namespace win;
AS>}

AS>// реализация
AS>namespace fw
AS>{
AS>  namespace win
AS>  {
AS>    namespace io
AS>    {
AS>      struct io_impl
AS>      {
AS>      };
AS>    }
AS>  }
AS>}

AS>// то, что видит пользователь

AS>namespace fw
AS>{
AS>  namespace io
AS>  {
AS>    // using namespace fw::win::io
AS>    struct io_front: io_impl // ошибка компиляции
AS>    {
AS>    };
AS>  }
AS>}
AS>

AS>Для чего это нужно — есть кроссплатформенный фреймворк, реализация для каждой платформы располагается в неймспейсе этой платформы. В зависимости от опций компиляции "морда" собирает это дело при помощи using директив в неймспейс интерфейса фремворка. Сейчас, кроме настройки, которая происходит автоматически, если есть вложенные "ниже" неймспейсы, приходится делать дополнительный using в интерфейсе с пользователем. Не сложно, но и не камильфо.

AS>Что хочется.

AS>1. Понять причину ошибки компиляции, в смысле, где в стандарте посмотреть (3.4.6 и 7.3 просмотрел, вроде ничего похожего).

fw::win::io и fw::io это разные namespaces.

7.3.1/3
The original-namespace-name in an extension-namespace-definition shall have previously been defined in
an original-namespace-definition in the same declarative region.

7.3.4/1
A using-directive does not add any members to the declarative region in which it appears.



AS>1 Добиться эффекта, чтобы fw::io мержилось с fw::io(from win) без дополнительного using.


Без дополнительного никак, но его можно вынести как-нибудь так:



// fw/details/config.h
// ...
namespace fw
{
  namespace platform = win;
}

// fw/details/io.h
#include "config.h"
namespace fw
{
  namespace io 
  { 
    using namespace platform::io;
  }
}

// то, что видит пользователь
// fw/io.h
#include "details/io.h"
namespace fw
{
  namespace io
   {
      struct io_front : io_impl
      {
      };
   }
}
Re[3]: nested namespaces linking
От: Erop Россия  
Дата: 11.08.09 23:05
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Повторюсь. В той схеме, что привел я — не нужно вообще ничего линковать _явно_, правила линка неймспейсов определяются в конфигурации, тот, кто пишет реализации, даже про них не знает. Если не пользует дополнительных неймспейсов Вот это, собственно, и надо как-то раскрутить. Один вариант решения этой проблемы я знаю, и написал о нем — меня он не устраивает.


Я так понял, что ты хочешь написать несколько реализаций библиотеки, а в конфигурилке что-то такое определить, что бы само собой оказались вытащенными в самый внешний нэймспаэс нужные из реализаций?

Ну вот если я верно тебя понял, то я и предлагаю тебе написать в win специфичное для win, потом, в конфигурилке можно сделать другое имя для win (скажем current_OS_spec), и разработчик win::io, unix::io, mac::io сможет написать где-то:
namespace io = current_OS_spec::io;

А можно и так:
namespace win {}
namespace unix {}
//...
namespace cur_OS_spec = win;
это всё в конфигурилке, а теперь в библиотеке:
namespace win {
    namespace io {
        // тут то, что специфично для win::io
    }
}
namespace io {
    using cur_OS_spec::io; // подняли специфичную часть в io

    //  тут неспецифичная часть.
}


Другой путь -- в неспецифичной части явно юзать cur_OS_spec::io, а пользователя избавить от такой нужды, подняв нужные для него идентификаторы во внешний io...

Как-то так.
Правда я пока так и не уверен, что понял, что тебе на самом деле надо?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: nested namespaces linking
От: vadimcher  
Дата: 12.08.09 00:29
Оценка: 7 (2)
Здравствуйте, Andrew S, Вы писали:

AS>Что хочется.

AS>1. Понять причину ошибки компиляции, в смысле, где в стандарте посмотреть (3.4.6 и 7.3 просмотрел, вроде ничего похожего).
AS>1 Добиться эффекта, чтобы fw::io мержилось с fw::io(from win) без дополнительного using.
AS>2. Возможно, есть способ как то порефакторить это, дабы избежать подобных или других проблем. Например, есть мысли неймспейсы реализации расположить в другом порядке: fw::io::win. Как в этом случае обеспечить автоматические линки неймспейсов, не очень понятно (делать include внутри неймспейсов как то некошерно, хотя в данном случае... не знаю, в общем, не по фен шую).

Я так понял, твой вопрос на счет ошибки следующий: есть класс io_impl, определенный в fw::win::io, в самом fw есть using namespace win, который позволяет использовать имена, в том числе io_impl, из fw::win::io так, как будто они в fw::io. А именно, следующий код не вызовет ошибки:
#include <iostream>

namespace fw {
    namespace debug {
        namespace io {
            class A { public: A() { std::cout << "debug" << std::endl; } };
        }
    }
    namespace release {
        namespace io {
            class A { public: A() { std::cout << "release" << std::endl; } };
        }
    }

    #ifdef _DEBUG
        using namespace debug;
    #else
        using namespace release;
    #endif
} // namespace fw

void main(void) {
    fw::io::A a;
}

Однако, если попытаться использовать теперь этот факт в стиле:
namespace fw {
    namespace io {
        class B: public A {} // error
    }
}

то компилятор даст ошибку. Твой вопрос: почему. Дело в том, что namespace работают по следующему принципу: когда ты указываешь fw::io::A, то компилятор смотрит, есть ли элемент io внутри fw -- нет, а внутри namespace-ов, которые объявлены как using внутри fw -- есть, а именно внутри debug (или release) есть namespace io, значит используем его, далее, есть ли там класс A -- да. Теперь, допустим, что ты добавил те строчки, что ниже. Ты ОПРЕДЕЛИЛ namespace io внутри fw, теперь, когда копилятор встречает запись fw::io, он смотрит, есть ли io внутри fw -- да, значит это оно и есть (и теперь fw::io никакого отношения к fw::win::io не имеет, т.к. io найдено внутри fw), и далее -- есть ли class A внутри namespace io? -- нет!

Более того, чтобы убить работоспособность первого кода достаточно внутрь namespace fw добавить просто namespace io {} и все! Теперь строчки fw::io::A будут интерпретироваться как fw::io, а не как fw::debug::io или fw::release::io, а там класса A нет -- не скомпилируется.

Вот простой пример, который демонстрирует то, как понимаются имена внутри:
#include <iostream>

namespace A {
    char ch = 'A';
}
namespace B {
    char ch = 'B';
    char ch2 = '2';
}
namespace C {
    using namespace A;
}
namespace D {
    using namespace A;
    using namespace B;
}
namespace E {
    using namespace A;
    using namespace B;
    char ch = 'E';
}

void main(void) {
    std::cout << C::ch << std::endl; // A
//    std::cout << D::ch << std::endl; // error!
//    std::cout << D::A::ch << std::endl; // error!
    std::cout << D::ch2 << std::endl; // 2
    B::ch2 = '3';
    std::cout << D::ch2 << std::endl; // 3
    std::cout << E::ch << std::endl; // E
//    std::cout << E::A::ch << std::endl; // error!
    std::cout << E::ch2 << std::endl; // 3
}

А вот зайца кому, зайца-выбегайца?!
http://files.rsdn.org/53829/avotzaitsakomu_sale.png
Re[4]: nested namespaces linking
От: Andrew S Россия http://alchemy-lab.com
Дата: 12.08.09 09:50
Оценка:
AS>>Повторюсь. В той схеме, что привел я — не нужно вообще ничего линковать _явно_, правила линка неймспейсов определяются в конфигурации, тот, кто пишет реализации, даже про них не знает. Если не пользует дополнительных неймспейсов Вот это, собственно, и надо как-то раскрутить. Один вариант решения этой проблемы я знаю, и написал о нем — меня он не устраивает.

E>Я так понял, что ты хочешь написать несколько реализаций библиотеки, а в конфигурилке что-то такое определить, что бы само собой оказались вытащенными в самый внешний нэймспаэс нужные из реализаций?


E>Ну вот если я верно тебя понял, то я и предлагаю тебе написать в win специфичное для win, потом, в конфигурилке можно сделать другое имя для win (скажем current_OS_spec), и разработчик win::io, unix::io, mac::io сможет написать где-то:

E>namespace io = current_OS_spec::io;

Нет, как раз я про другое. Разработчик специфичной реализации спокойно обитает в неймспейсе своей платформы. Там как раз проблем нет.
Надо то, что он сделает в неймспейсе свой платформы потом вытащить в общий неймспейс. Вот тут и начинаются проблемы.

E>А можно и так:
E>namespace win {}
E>namespace unix {}
E>//...
E>namespace cur_OS_spec = win;
E>
это всё в конфигурилке, а теперь в библиотеке:
namespace win {
E>    namespace io {
E>        // тут то, что специфично для win::io
E>    }
E>}
E>namespace io {
E>    using cur_OS_spec::io; // подняли специфичную часть в io

E>    //  тут неспецифичная часть.
E>}
E>


E>Другой путь -- в неспецифичной части явно юзать cur_OS_spec::io, а пользователя избавить от такой нужды, подняв нужные для него идентификаторы во внешний io...


Ну примерно так сеейчас и сделано.. Но ведь криво же...
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[5]: nested namespaces linking
От: Erop Россия  
Дата: 12.08.09 12:31
Оценка:
Здравствуйте, Andrew S, Вы писали:

E>>Другой путь -- в неспецифичной части явно юзать cur_OS_spec::io, а пользователя избавить от такой нужды, подняв нужные для него идентификаторы во внешний io...


AS>Ну примерно так сеейчас и сделано.. Но ведь криво же...


Почему криво? Хотя мне первый путь больше нравится, чем второй, так как разработчик платформы сам решает какие потроха публиковать, а какие нет...

Да и пользователь знает, что может отвалится на другой платформе, а что нет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: nested namespaces linking
От: Andrew S Россия http://alchemy-lab.com
Дата: 12.08.09 14:50
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Andrew S, Вы писали:


E>>>Другой путь -- в неспецифичной части явно юзать cur_OS_spec::io, а пользователя избавить от такой нужды, подняв нужные для него идентификаторы во внешний io...


AS>>Ну примерно так сеейчас и сделано.. Но ведь криво же...


E>Почему криво? Хотя мне первый путь больше нравится, чем второй, так как разработчик платформы сам решает какие потроха публиковать, а какие нет...


E>Да и пользователь знает, что может отвалится на другой платформе, а что нет...


Ну так оно сейчас так примерно и выглядит. Хотелось чтобы линковалось "само". Видимо, не получится. Ок, спасибо за ответы.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.