我正在尝试使用标签并对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,异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)
无论哪种方式,您都必须稍微更改设计。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句