我正在尝试使用标签和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 ...);
?