правильный синтаксис для вывода возвращаемого значения статической функции-члена зависимого типа

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

struct
t_In
{
};

struct
t_Out
{
    static auto
    Method(t_In &) -> t_Out
    {
        return(t_Out());
    }
};

template<typename tp_Out, typename tp_In, typename tp_Enable = void> struct
t_Template;

template<typename tp_Out, typename tp_In> struct
t_Template
<
    tp_Out
,   tp_In
,   typename ::std::enable_if
    <
        ::std::is_same
        <
            decltype
            (
                ::std::remove_cv // adding typename here makes Method look like type
                <
                    typename ::std::remove_reference
                    <
                        tp_Out
                    >::type
                >::type::Method(::std::declval<tp_In>()) // Err: does not evaluate to function ...
            )
        ,   tp_Out
        >::value
    >::type
>
{
};

Изменить: компилятор VS2013, обратите внимание, что я даже ничего не создаю, всплывающее сообщение об ошибке только из этого шаблона


person trbvm    schedule 11.08.2015    source источник
comment
он работает с std::declval<tp_In&>()?   -  person Piotr Skotnicki    schedule 11.08.2015
comment
@ Piotr Skotnicki нет, сообщение об ошибке остается прежним   -  person trbvm    schedule 11.08.2015
comment
@trbvm где это сообщение об ошибке?   -  person Piotr Skotnicki    schedule 11.08.2015
comment
@ Bo Persson это приводит к дополнительным ошибкам "Метод": символ не является ни шаблоном класса, ни шаблоном функции   -  person trbvm    schedule 11.08.2015
comment
@Piotr Skotnicki, где находится комментарий // Err:   -  person trbvm    schedule 11.08.2015
comment
... и то, что следует далее, не оценивается как функционирующее ...? как создать экземпляр своего t_Template, какой компилятор вы используете?   -  person Piotr Skotnicki    schedule 11.08.2015
comment
Полное сообщение @Piotr Skotnicki - это ошибка C2064: термин не оценивает функцию, принимающую 1 аргумент, ничего больше (это VS2013)   -  person trbvm    schedule 11.08.2015


Ответы (2)


Одна из ваших проблем заключается в том, что std::declval возвращает ссылку rvalue, которая не может быть привязана к неконстантной ссылке lvalue, такой как t_In&.

Достаточно чистое решение - использовать void_t и std::declval<tp_In&>:

//standard void_t implementation
template <typename...> struct voider { using type = void; };
template <typename...Ts> using void_t = typename voider<Ts...>::type;

//primary template
template<typename tp_Out, typename tp_In, typename tp_Enable = void>
struct t_Template;

//for when tp_Out has a static member function called Method 
//taking an lvalue reference to tp_In
template<typename tp_Out, typename tp_In>
struct t_Template
<tp_Out, tp_In, void_t<decltype(tp_Out::Method(std::declval<tp_In&>()))>>
{
};
person TartanLlama    schedule 11.08.2015
comment
К вашему сведению: OP использует MSVC (2013!) - person Piotr Skotnicki; 11.08.2015
comment
Ах, да, MSVC не поддерживает выражение SFINAE, поэтому это не будет работать, если OP не переключит компилятор. - person TartanLlama; 11.08.2015
comment
Это приводит к той же ошибке C2064: term не оценивает функцию, принимающую 1 аргумент. обратите внимание, что я даже ничего не создаю. - person trbvm; 11.08.2015
comment
Я думаю, это проблемы с MSVC. Он отлично работает в clang. - person TartanLlama; 11.08.2015
comment
@ TartanLlama, похоже, так - person trbvm; 11.08.2015

tl; dr; Синтаксис type :: StaticMemberFunctionName в VS2013 нарушается при использовании в параметрах шаблона, причудливые выражения, такие как decltype (decltype (* & tp_Out :: Method) (:: std :: declval ())), даже приводят к внутренним ошибкам компилятора. Однако этот синтаксис все еще работает, когда используется где-либо еще, поэтому мне удалось найти обходной путь:

template<typename tp_Out, typename tp_In> struct
t_MethodReturnValueDeducer
{
    typedef decltype
    (
        ::std::remove_cv
        <
            typename ::std::remove_reference
            <
                tp_Out
            >::type
        >::type::Method(::std::declval<tp_In &>())
    ) t_Deduced; 
};

template<typename tp_Out, typename tp_In, typename tp_Enable = void> struct
t_Template;

template<typename tp_Out, typename tp_In> struct
t_Template
<
    tp_Out
,   tp_In
,   typename ::std::enable_if
    <
        ::std::is_same
        <
            typename t_MethodReturnValueDeducer<tp_Out, tp_In>::t_Deduced
        ,   tp_Out
        >::value
    >::type
>
{

};

Я надеюсь, что это будет полезно для людей, которые все еще борются с VS2013 ...

person trbvm    schedule 11.08.2015