2013-05-31 2 views
2

Во-первых, извините, если я делаю большие английские ошибки, я французский, но я стараюсь писать как можно лучше! Ну, я борюсь с C++ 11 вариационным шаблоном. Я хочу сделать что-то немного сложное.Специализирующийся тип возврата для вариационного шаблона

Действительно, я хочу специализировать тип возврата моего шаблона, зная, что это вариационный шаблон.

Моя цель состоит в том, чтобы добиться чего-то вроде:

l.callFun<int>("addition", 40, 1, 1); 

специализация соответствует типу возврата, которую пользователь. Это привязка Lua, поэтому я не могу определить тип возвращаемого значения, если пользователь не уточняет его (очевидно, по умолчанию, если нет специализации, будет пустое возвращение). Позже это имя функции, которая вызывается в Lua. Затем 3 целых числа соответствуют моему вариационному шаблону.

Прямо сейчас, мой шаблон выглядит так:

template <typename Z, typename T, typename... U> 
Z LuaScript::callFun(const std::string& name, const T& head, const U&... tail); 

Но, похоже, что я не могу сделать частичную специализацию шаблонной функции. Есть ли кто-нибудь, кто мог бы мне помочь?

спасибо!

+0

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

+0

То, что я хочу специализировать, это тип возврата! – Theo13

+0

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

ответ

1

справки и документации очень высоко pheedbaq, но в конце концов, я пришел с действительно простое решение. Я не сделал этого так, поэтому я буду экспериментировать с этим путем перегрузки оператора благодаря вам;)

Что я сделал, это упаковывание вариационных аргументов и вызов другого шаблона для специализации по возврату тип. Так что у меня есть что-то вроде этого:

template <typename Z, typename... T> 
Z LuaScript::callFun(const std::string& name, const T&... args) 
{ 
    Z ret; 
    callFunReal(args); 
    [...] 
    ret = returnType<Z>(); 
    return (ret); 
} 

Это было на самом деле довольно просто, но не мог видеть, как именно это сделать ... Спасибо всем! :)

+0

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

+0

Да, я знаю, это просто, что я должен подождать один день, чтобы отметить мой собственный ответ в качестве ответа, я просто жду :) – Theo13

+0

Lol, я понимаю. Просто для удовольствия я внес изменения в свой код, который использует совершенную пересылку и позволяет пользователю совершать вызов, как вы изначально описывали. –

1

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

template<typename Z> 
struct callFun_helper { 
    template<typename T, typename... U> 
    static Z help(const std::string& name, const T& head, const U&... tail) { 
     Z thing; 
     //do something with "thing" 
     return thing; 
    } 
}; 

template<typename Z, typename S, typename T, typename... U> 
auto callFun(S&& s, T&& t, U&&... u) 
-> decltype(callFun_helper<Z>::help(std::forward<S>(s), std::forward<T>(t), std::forward<U>(u)...)) { 
    return callFun_helper<Z>::help(std::forward<S>(s), std::forward<T>(t), std::forward<U>(u)...); 
} 

//main 
callFun<string>("addition", 40, 1, 1)  

Ссылка ниже может помочь вам с частичной специализации шаблона, если вы хотите узнать больше о том, что вы можете/не можете делать с ним. Кроме того, не забудьте отметить ответ, если вы хотите продолжать получать ответы в будущем здесь на StackOverflow :)

Why Not Specialize Function Templates?

1

Решение, которое не требует изменения вашего интерфейса является переадресация вызова функции в template<> class, где вы можете специализироваться на содержание сердца:

template<typename R, typename... Ts> 
struct DoCallFun { 
    R operator()(LuaScript* self, std::string const& name, Ts&&... ts) { 
    } 
}; 

template <typename Z, typename... T> 
Z LuaScript::callFun(const std::string& name, Ts&&... ts) { 
    return DoCallFun<Z, Ts...>()(this, name, head, std::forward<Ts>(ts)...) 
} 

и мы реализуем тело callFun в DoCallFun. Если ему нужен доступ к закрытым переменным в LuaScript, мы делаем DoCallFun a friend.

Теперь лучшим решением может быть использование «признаков class» для большей части зависимого поведения типа return.Если вам нужно вызвать другую функцию, основанную на типе return, вместо того, чтобы писать один и тот же callFun один раз для каждого типа return с небольшой разницей, вы можете создать «черты class», где вы изолируете разницу на основе типа return.

Предположим, вам нужно вызвать int CallAndReturnInt(...) если тип int и double CallAndReturnDouble(...) если тип double. Вместо того, чтобы два тела callFun, написать черты класса:

template<typename T> 
struct lua_return_traits; 
template<> 
struct lua_return_traits<int> { 
    template<typename... Ts> 
    static int call_and_return(Ts&&... ts) { 
    return CallAndReturnInt(std::forward<Ts>(ts)); 
    } 
}; 
template<> 
struct lua_return_traits<double> { 
    template<typename... Ts> 
    static double call_and_return(Ts&&... ts) { 
    return CallAndReturnDouble(std::forward<Ts>(ts)); 
    } 
}; 

и аналогичные методы для других способов ваш метод должен отличаться в зависимости от типа return.