簡體   English   中英

模板參數推斷失敗

[英]Template argument deduction fails

我正在嘗試使用tags和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 ...);

編譯器可以從模板函數參數中推導出類型模板參數AB ,以及非類型模板參數N ,其類型由以下結構組成( Stroustrup 23.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)

其中args是不允許推導的參數列表, args_AN是參數列表,通過遞歸應用上述規則可以從中確定AN 如果不能以這種方式推斷出所有參數,則呼叫是不明確的。

你的構造

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 ,與std :: forward的情況完全相同。 不幸的是,這非常不方便。 在允許演繹的同時使其方便的幾種方法是

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

要么

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

無論哪種方式,您都必須稍微改變您的設計。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM