Search code examples
c++templatesdecltype

correct syntax for deducing return value of static member function of dependent type


I can't figure out the correct syntax for deducing return value of static member function of dependent type. I've already tried a dozen of combinations, including use of ::std::result_of and none of them seem to work. Here is the variant that looks most promising (at least works in non-template context):

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
>
{
};

Edit: compiler VS2013, note that I don't even instantiate anything, error popup just from this template alone


Solution

  • tl;dr; type::StaticMemberFunctionName syntax in VS2013 is broken when used in template parameters, fancy expressions like decltype(decltype(*&tp_Out::Method)(::std::declval())) even lead to internal compiler errors. However this syntax still works when used anywhere else, so I've managed to find a workaround:

    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
    >
    {
    
    };
    

    I hope this will be helpful for people still struggling with VS2013...