我有一个函数set_data
,我必须以不同的方式实现它所采用的不同类型。例如,这是尝试根据输入类型实现两个重载。如果它是基础,非void
和非nullptr_t
,则在第一次实现时处理它。如果它是std::string
或char
缓冲区,请以第二种方式处理它。
struct field
{
template<typename TDataType, typename=void>
void set_data(TDataType data, size_t index = 0);
};
template<typename TDataType, typename = typename
std::enable_if< std::is_fundamental<TDataType>::value &&
std::is_same<TDataType, nullptr_t>::value == false &&
std::is_same<TDataType, void>::value == false>::type>
void field::set_data(TDataType data, size_t index /* = 0 */)
{
}
template<typename TDataType, typename = typename
std::enable_if< std::is_same<std::string const &, TDataType> ||
std::is_same<char const *, TDataType>>::type>
void field::set_data(TDataType data, size_t index /* = 0 */)
{
}
然后我打电话给:
field f;
int x = 10;
f.set_data(x);
编译器向我抛出错误。
defs.h(111): error C2995: 'void messaging::field::set_data(TDataType,size_t)' : function template has already been defined
如何解决此问题?
在Visual Studio 2013上
答案 0 :(得分:4)
您正在尝试定义类在之外的重载,这当然是不允许的。或者您可能尝试为成员函数模板提供两个部分特化,但函数模板不能部分专门化。
你需要摆脱公共声明并将两个重载移到类中。但是,你必须使它们与众不同。您可以通过给其中一个额外的模板参数(并向第二个重载添加一些缺少的::value
)来做到这一点:
struct field
{
template<typename TDataType, typename = typename
std::enable_if< std::is_fundamental<TDataType>::value &&
std::is_same<TDataType, std::nullptr_t>::value == false &&
std::is_same<TDataType, void>::value == false>::type>
void set_data(TDataType data, size_t index = 0)
{
}
template<typename TDataType, typename = void, typename = typename
std::enable_if< std::is_same<std::string const &, TDataType>::value ||
std::is_same<char const *, TDataType>::value>::type>
void set_data(TDataType data, size_t index = 0)
{
}
};
此外,请注意,如果函数模板的参数是按值传递,则模板参数永远不会推导为引用类型。因此,如果在调用站点上明确指定了模板参数is_same<std::string const &, TDataType>
,则std::string const &
只能为真。您可能只想检查std::string
来替换它。甚至可能值得投入一些std::remove_reference
和std::remove_cv
来正确处理显式指定的模板参数。
答案 1 :(得分:3)
SFINAE {(1}}对(成员)函数(如示例中)的通常用法是返回类型(而不是其他模板参数)。这会给你
enable_if
答案 2 :(得分:2)
在这样的模板参数上使用SFINAE并不起作用,我认为我不能100%确定原因(编辑: Agnew的答案解释了它&#39 ; s因为模板是无法区分的)。如果您在返回类型上使用std::enable_if
,并在类中移动定义,那么它可以工作(使用gcc和clang测试):
struct field
{
template<typename TDataType>
void set_data(TDataType data, size_t index = 0) {}
template<typename TDataType>
typename std::enable_if<std::is_fundamental<TDataType>::value &&
!std::is_same<TDataType, std::nullptr_t>::value &&
!std::is_same<TDataType, void>::value,
void>::type
set_data(TDataType data, size_t index /* = 0 */)
{
}
template<typename TDataType>
typename std::enable_if<std::is_same<std::string const &, TDataType>::value ||
std::is_same<char const *, TDataType>::value,
void>::type
set_data(TDataType data, size_t index /* = 0 */)
{
}
};
(我还修复了其他一些错误,即没有要求第二次重载的value
std::is_same
成员,而没有指定{{1}的命名空间})。