2013-12-05 6 views
1

Учитывая вызываемый объект (функция) a, и аргумент b (или ряд аргументов), я хотел бы вывести тип, возвращаемый из f считая, что f перегружен множеством подписей ,Выведение типа для перегруженных функций - выделки

один из моих многочисленных попыток

#include <iostream> 
#include <cstdint> 
#include <string> 
#include <functional> 
#include <utility> 
#include <typeinfo> 

int foo(uint32_t a) { return ((a + 0) * 2); } 

bool foo(std::string a) { return (a.empty()); } 

/*template <typename A, typename B> auto bar(A a, B b) -> decltype(a(b)) { 
    return (a(b)); 
}*/ 

/*template <typename A, typename B> decltype(std::declval<a(b)>()) bar(A a, B b) 
{ 
    return (a(b)); 
}*/ 

template <typename A, typename B> void bar(std::function<A(B)> a, B b) { 
    std::cout << a(b) << "\n"; 
} 

int main() { 

    // the following 2 lines are trivial and they are working as expected 
    std::cout << foo(33) << "\n"; 
    std::cout << typeid(decltype(foo(std::string("nothing")))).name() << "\n"; 

    std::cout << bar(foo, 33) << "\n"; 
    //std::cout << bar(foo, std::string("Heinz")) << "\n"; 

    return (0); 
} 

и 2 шаблоны опций закомментирована и включены в предыдущем коде.

Я использую declval result_of auto decltype без везения.

Как работает процесс перегрузки при компиляции?

Если кто-то хочет знать, почему я пытаюсь проявить творческий подход к этому, это то, что я пытаюсь реализовать некоторые Currying в C++ 11 в работоспособном/опрятном виде.

+0

Я не уверен, понимаю ли вы то, о чем вы спрашиваете, вы имеете в виду: Как я могу указать возвращаемый тип f() с учетом аргументов? – ScarletAmaranth

+0

@ScarletAmaranth yep – user2485710

+0

Что не так с 'decltype (f (b))'? – Casey

ответ

4

Проблема в том, что вы не можете легко создать объект функции из набора перегрузки: когда вы заявляете foo или &foo (функция распадается на указатель на функцию в большинстве случаев, я думаю,), вы не получаете объект, но получаете набор перегрузки. Вы можете сказать компилятору, который перегружает вас, вызывая его или предоставляя его подпись. Насколько я могу судить, вы тоже не хотите.

Единственный подход, я в курсе, чтобы превратить вашу функцию в реальной функции объекта, что делает проблему уйти:

struct foo_object 
{ 
    template <typename... Args> 
    auto operator()(Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) { 
     return foo(std::forward<Args>(args)...); 
    } 
}; 

С этой оберткой, которая, к сожалению, необходимое для каждого имени, вы можете тривиальным вывести тип возвращаемого, например:

template <typename Func, typename... Args> 
auto bar(Func func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) { 
    // do something interesting 
    return func(std::forward<Args>(args)...); 
} 

int main() { 
    bar(foo_object(), 17); 
    bar(foo_object(), "hello"); 
} 

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

+0

, так что 'foo_object' действует как прокси-сервер так же, как при создании нового объекта с отличной пересылкой? EDIT: плюс очевидное использование 'decltype' для вывода типа – user2485710

+0

@ user2485710:' foo_object' - это по сути то, что позволяет коду назвать набор перегрузки: тип 'foo_object' - это то, что можно назвать и объект его можно создать, но, тем не менее, зная, какая перегрузка выбрана. Как только аргументы доступны, компилятор затем выработает разрешение перегрузки. По общему признанию, можно построить случаи, когда можно найти разные перегрузки ... –

+0

Я хочу сказать, что для упрощения концепции в C++ 11 всегда есть новые методы, основанные на основном различии между временем «Instantiation» и время, когда компилятор завершает подстановку аргументов, иногда с помощью некоторого правила свертывания ссылки, на языке, таком как Haskell, так просто думать о типе, который на самом деле шаблоны на C++ не позволяют вам абстрагировать тип , они просто заполнители для чего-то, что нуждается в «немедленной» замене. – user2485710

2

Это действительно уже реализовано для вас std::result_of. Вот возможная реализация

template<class> 
struct result_of; 

// C++11 implementation, does not satisfy C++14 requirements 
template<class F, class... ArgTypes> 
struct result_of<F(ArgTypes...)> 
{ 
    typedef decltype(
        std::declval<F>()(std::declval<ArgTypes>()...) 
        ) type; 
}; 
+0

Вы можете показать пример с перегруженной функцией? – user2485710

+0

Я просто хотел бы вызвать еще одну шаблонную функцию 'foo', где' T' является выведенным как 'foo ()' прямо внутри этого шаблона. Я пытаюсь это сделать сейчас ... – user2485710

+0

Я думаю, что OP имеет обратную задачу: выбор перегрузки 'foo' на основе существования результата типа. –

3

Если Foo перегружен, вам нужно использовать следующее:

#include <type_traits> 

int foo(int); 
float foo(float); 

int main() { 
    static_assert(std::is_same<decltype(foo(std::declval<int>())), int>::value, "Nope."); 
    static_assert(std::is_same<decltype(foo(std::declval<float>())), float>::value, "Nope2."); 
} 

Если это не так, то это будет достаточно:

#include <type_traits> 
bool bar(int); 

int main() { 
    static_assert(std::is_same<std::result_of<decltype(bar)&(int)>::type, bool>::value, "Nope3."); 
} 

Да, это многословным, потому что вы пытаетесь явно извлекать то, что для вас подразумевает неявная ad-hoc перегрузка.

+0

слишком сложный и многословный ... это в основном сводит на нет мою цель сделать это более «функциональным». – user2485710

Смежные вопросы