2012-03-25 3 views
48

Если у меня есть класс Foo в пространстве имен бар:C++ 11: Как выполнить функцию?

namespace bar 
{ 
    class Foo { ... } 
}; 

Я могу тогда:

using Baz = bar::Foo; 

и теперь это так же, как я определил класс в моем пространстве имен с именем Baz.

Можно ли сделать то же самое для функций?

namespace bar 
{ 
    void f(); 
} 

И потом:

using g = bar::f; // error: ‘f’ in namespace ‘bar’ does not name a type 

Что такое чистый способ сделать это?

Решение также должно содержать функции шаблона.

Определение: Если какой-то объект В является псевдоним А, чем если какие-либо или всех вхождений (не деклараций или определений, конечно) из A заменены B в исходном коде, чем (раздели), порожденную код остается прежним. Например, typedef A B является псевдонимом. #define B A - псевдоним (по крайней мере). T& B = A не является псевдонимом, B может эффективно реализоваться как косвенный указатель, если «unaliased» A может использовать «непосредственную семантику».

+0

, что это такое, что вы хотите достичь? Если вы заявляете, что вам действительно нужно, возможно, будет возможно предоставить альтернативы, но, как бы то ни было, неясно, что вы имеете в виду под псевдонимом * –

+1

@ DavidRodríguez-dribeas: Существует мало путаницы в отношении того, что означает «псевдоним» в выше. В общем случае, если B является псевдонимом A, чем если вы замените использование A на B, то сгенерированный код останется неизменным. Почему вы хотите, чтобы это было просто. Я хочу дать библиотечной функции второе имя/пространство имен. Я подозреваю, что самый чистый способ - просто обернуть вызов старого имени с помощью функции always_inline нового имени. Обертка будет скомпилирована, оставив что-то неотличимое от прямого вызова старого имени по желанию. –

+0

Ну, еще не ясно, например, соответствует ли указатель функции, определенный в пространстве имен назначения, вашим требованиям или нет. Это не одна и та же функция, но ваша программа может идти вперед, даже не замечая (есть ситуации, когда это имеет значение, но они не так уж и общие). Кроме того, вы не указали, нужно ли вам другое имя или просто другое пространство имен, поэтому * использование-декларация * также может удовлетворить ваши потребности ... Не забудьте спросить о том, что вам нужно, поскольку это то, что позволяет использовать различные альтернативы что может не соответствовать вашему текстовому описанию. –

ответ

50

Вы можете определить функцию псевдоним (с некоторой работой), используя совершенную переадресацию:

template <typename... Args> 
auto g(Args&&... args) -> decltype(f(std::forward<Args>(args)...)) { 
    return f(std::forward<Args>(args)...); 
} 

Это решение не распространяется, даже если f перегружен и/или шаблон функции.

+3

Он не применяется, если 'f' является шаблоном функции, который не может использовать вычет типа. –

+0

@ R.MartinhoFernandes: Можете ли вы привести пример такого шаблона функции, который не может использовать вычет типа? –

+3

@ user1131467 Любая функция, которая использует аргумент шаблона для определения своего типа возврата (например, 'boost :: lexical_cast') или использует аргумент шаблона в качестве аргумента * de facto * (например,' std :: get'). –

17

Классы типов, так что они могут быть совмещенным с typedef и using (в C++ 11).

Функции гораздо больше похожи на объектов, поэтому нет механизма для их псевдонимов. В лучшем случае вы можете использовать указатели на функции или функции ссылки:

void (*g)() = &bar::f; 
void (&h)() = bar::f; 

g(); 
h(); 

В том же ключе, что нет никакого механизма для наложения переменных (сокр не через указатели или ссылки).

+0

Итак, что здесь происходит: 'auto g = bar :: f;'? –

+1

@ user1131467: Вы объявляете и определяете новый объект. –

+1

Каков тип этого объекта? И что здесь происходит: 'inline void g() {bar :: f(); } ' –

11

Абсолютно:

#include <iostream> 

namespace Bar 
{ 
    void test() 
    { 
     std::cout << "Test\n"; 
    } 


    template<typename T> 
    void test2(T const& a) 
    { 
     std::cout << "Test: " << a << std::endl; 
    } 
} 

void (&alias)()  = Bar::test; 
void (&a2)(int const&) = Bar::test2<int>; 

int main() 
{ 
    Bar::test(); 
    alias(); 
    a2(3); 
} 

Попытка:

> g++ a.cpp 
> ./a.out 
Test 
Test 
Test: 3 
> 

Ссылка является псевдонимом к существующему объекту.
Я только что создал ссылку на функцию. Ссылка может использоваться точно так же, как и исходный объект.

+0

Разве это не требует дополнительного разыменования при вызове псевдонима? Также как это работает для функций шаблона? –

+0

AS вы можете видеть, что он отлично работает. С шаблонами он работает для конкретных экземпляров, вы не можете использовать шаблон, но вы можете использовать определенную версию шаблона. –

+5

Лучшая идиома для этого: 'constexpr auto & alias = Bar :: test;'. Часть 'constexpr' гарантирует, что ссылка будет заменена во время компиляции. Однако функция 'auto' не будет работать для шаблонной функции. –

7

Это не стандарт C++, но большинство компиляторов предоставляют способ сделать это.С помощью GCC вы можете сделать это:

void f() __attribute__ ((weak, alias ("__f"))); 

Это создает символ f как псевдоним для __f. С VC++ вы делаете то же самое так:

+0

И будет ли это работать с перегруженными функциями, шаблонами, всем? – einpoklum

+0

@einpoklum Да - ish. Вы можете заставить компилятор генерировать псевдоним для какой-либо конкретной функции, которую он генерирует, - это всего лишь точки входа в исполняемый объект с именами, назначенными им. Перегруженные функции - это просто функции, а имя искажено, чтобы отразить подпись функции. Функции шаблона не имеют исполняемых имен, но _instantiations_ этих функций шаблона делают - и компилятор может испускать для них псевдонимы. Много ли это для вас - другое дело. – Tom

+0

Одна из трудностей заключается в том, что вы должны использовать имя искаженного символа для функции в объявлении 'alias()'. Ваш пример выглядит неправильно (по этой причине); или даже если это правильно в какой-то системе, это будет намного сложнее для функции с параметрами. – davmac

6

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

namespace bar { 
    void f(); 
} 

namespace baz { 
    using bar::f; 
} 

void foo() { 
    baz::f(); 
} 
+0

Я не знаю, почему это не принятый ответ: я просто попробовал, и он работает даже для функций шаблона (без необходимости иметь префикс с шаблоном , чтобы сделать это). Насколько я могу судить, он втягивает все перегрузки для имени. – Dennis

0

Вы можете использовать старые добрые макросы

namespace bar 
{ 
    void f(); 
} 

#define f bar::f 

int main() 
{ 
    f(); 
} 
Смежные вопросы