[英]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 ...);
?
編譯器可以從模板函數參數中推導出類型模板參數A
或B
,以及非類型模板參數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
是參數列表,通過遞歸應用上述規則可以從中確定A
或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
,與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.