模板参数推导失败

2024-01-20

我正在尝试使用标签和enable_if对模板参数实施约束。这是代码:

#include <type_traits>
#include <iostream>

template<typename Type>
struct tag {}; 

struct Atag {}; 
struct Btag {};

template<typename Type, typename Tag>
struct tag_enabled
{
    static_assert(
        std::is_same
        <
            typename tag<Type>::type, 
            Tag 
        >::value, 
        "Error: Type is not tagged with Tag."
    ); 

    typedef typename std::enable_if
    <
        std::is_same
        <
            typename tag<Type>::type, 
            Tag 
        >::value, 
        Type
    >::type type; 
};

template<typename A>
typename tag_enabled<A, Atag>::type
worker(
   typename tag_enabled<A, Atag>::type const & a
)
{
    A result; 

    std::cout << "Atag -> Atag" << std::endl;

    return result; 
}

template<typename A, typename B>
typename tag_enabled<A, Atag>::type
worker(
    typename tag_enabled<B, Btag>::type const & b
)
{
    A result; 

    std::cout << "Btag -> Atag" << std::endl;

    return result; 
}


template<typename A, typename ... Args>
A caller(Args ... args)
{
    return worker<A>(args ...);
}

struct test_a {}; 
struct test_b {}; 

template<>
struct tag<test_a>
{
    typedef Atag type; 
};

template<>
struct tag<test_b>
{
    typedef Btag type;
};

int main(int argc, const char *argv[])
{
    // caller int(int)
    test_a ta1; 
    test_b tb1; 

    auto ta2 = caller<test_a>(ta1); 

    // Why does this fail?  
    auto ta3 = caller<test_a>(tb1);

    return 0;
}

结果出现以下错误:

test-template.cpp: In instantiation of ‘A caller(Args ...) [with A = test_a; Args = {test_b}]’:
test-template.cpp:90:34:   required from here
test-template.cpp:63:30: error: no matching function for call to ‘worker(test_b&)’
     return worker<A>(args ...);
                              ^
test-template.cpp:63:30: note: candidates are:
test-template.cpp:35:1: note: template<class A> typename tag_enabled<A, Atag>::type worker(const typename tag_enabled<A, Atag>::type&)
 worker(
 ^
test-template.cpp:35:1: note:   template argument deduction/substitution failed:
test-template.cpp:63:30: note:   cannot convert ‘args#0’ (type ‘test_b’) to type ‘const type& {aka const test_a&}’
     return worker<A>(args ...);
                              ^
test-template.cpp:48:1: note: template<class A, class B> typename tag_enabled<A, Atag>::type worker(const typename tag_enabled<B, Btag>::type&)
 worker(
 ^
test-template.cpp:48:1: note:   template argument deduction/substitution failed:
test-template.cpp:63:30: note:   couldn't deduce template parameter ‘B’
     return worker<A>(args ...);

除最后一个错误外,所有错误都是可以预料和欢迎的。这tag_enabled应确保函数模板不会根据模板参数标签进行实例化。这个错误例如:

test-template.cpp:35:1: note:   template argument deduction/substitution failed:
    test-template.cpp:63:30: note:   cannot convert ‘args#0’ (type ‘test_b’) to type ‘const type& {aka const test_a&}’
         return worker<A>(args ...);

很好,因为我希望该函数的推导失败,因为它应该执行映射Atag -> Atag并不是Btag -> Atag。如果二参数函数模板可以工作,SFINAE 会(至少我希望如此)放弃这个候选函数。这是我关心的错误,为什么模板参数推导在这里失败:

test-template.cpp:48:1: note:   template argument deduction/substitution failed:
test-template.cpp:63:30: note:   couldn't deduce template parameter ‘B’
     return worker<A>(args ...);

?


编译器可以推导出类型模板参数,A or B和一个非类型模板参数,N,来自模板函数参数,其类型由以下结构组成 (斯特鲁斯特鲁普 http://www.stroustrup.com/4th.html23.5.2、ISO 14.8.2.1):

A
const A
volatile A
A*
A&
A[constant_expression]
type[N]
class_template<A>
class_template<N>
B<A>
A<N>
A<>
A type::*
A A::*
type A::*
A (*)(args)
type (A::*)(args)
A (type::*)(args)
type (type::*)(args_AN)
A (A::*)(args_AN)
type (A::*)(args_AN)
A (type::*)(args_AN)
type (*)(args_AN)

where args是一个不允许推导的参数列表,并且args_AN是一个参数列表,其中A or an N可以通过递归应用上述规则来确定。如果不能以这种方式推导出所有参数,则调用是不明确的。

你的构造

typename tag_enabled<B, Btag>::type const &

不具有上述形式之一,因此B不能从中推断出

template<typename A, typename B>
typename tag_enabled<A, Atag>::type
worker(typename tag_enabled<B, Btag>::type const & b)

B必须明确指定,正如情况一样标准::转发 http://en.cppreference.com/w/cpp/utility/forward。不幸的是,这很不方便。有几种方法可以使其方便,同时允许扣除

template<typename A, typename B, typename = typename std::enable_if <...> >
typename tag_enabled<A, Atag>::type
worker(B const& b)

or

template<typename A, typename B>
typename tag_enabled<A, Atag, B, Btag>::type
worker(B const& b)

不管怎样,你都必须稍微改变你的设计。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模板参数推导失败 的相关文章

随机推荐