Class class 之外的函数模板定义
Class function template definition outside of the class
所以我一直在编写自己的 unique_ptr class 并且我必须以与处理其他类型不同的方式处理数组。
template <typename TYPE, bool _arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//some methods
void reset();
};
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, _arr>::reset()
{
//some code...
}
问题是我希望重置方法仅适用于非数组分配,当使用 std::enable_if 时我收到错误:"A default template argument cannot be specified on the declaration of a member of a class template outside of its class" 尽管代码仍在编译
template<typename TYPE ,bool _arr>
class scoped_ptr final {
public:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE ,bool _arr>
template<typename = typename std::enable_if<!_arr>::type>
inline void scoped_ptr<TYPE, _arr>::reset()
{
}
我也试过这个,但是也报错:"template argument list must match parameter list"
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, false>::reset()
{
}
有没有人知道如何为数组禁用此方法?我知道我可以专门化 class scoped_ptr 但我想避免代码重复。有什么办法吗?
编辑:
阅读回复后,我将代码更改为:
template <typename TYPE, bool is_arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//Some methods
template<bool _arr = is_arr, typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE, bool is_arr>
template<bool, typename>
inline void scoped_ptr<TYPE, is_arr>::reset()
{
}
代码编译没有错误,直到我尝试调用方法:
int main() {
scoped_ptr<int> ptr = new int;
ptr.reset();
}
那是我收到错误的时候:"void scoped_ptr«int,false»::reset(void): could not deduce template argument for «unnamed-symbol»"
但是如果我在 class 中编写实现,错误就会消失。我该如何解决这个问题?
如果你想让 reset()
SFINAE 友好,请将其设为假模板:
template<bool is_arr = _arr, typename = std::enable_if_t<is_arr>>
void reset();
请注意,SFINAE 在实例化模板时起作用,条件应取决于模板参数。这不是有效的 SFINAE 结构:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
如果您不关心 SFINAE 的友好性,请在 reset()
中使用 static_assert()
。
编辑.
考虑以下 simple code 作为有效和无效 SFINAE 的演示:
template<class T, bool f = std::is_integral_v<T>>
struct S {
// template<typename = std::enable_if_t<f>> // (invalid)
template<bool _f = f, typename = std::enable_if_t<_f>> // (valid)
void reset() {}
};
template<class T, typename = void>
struct has_reset : std::false_type {};
template<class T>
struct has_reset<T, std::void_t<decltype(std::declval<T>().reset())>> : std::true_type {};
void foo() {
has_reset<S<int>>::value;
has_reset<S<void>>::value;
}
如果将 (valid)
行替换为 (invalid)
行,它将无法编译。
编辑 2.
在class外定义成员函数时,不重复模板参数的默认值:
template<class T, bool f>
template<bool, typename>
void S<T, f>::reset() { }
编辑 3.
出于某种原因(我想是编译器错误)MSVC 拒绝了这个定义并出现错误:"Could not deduce template argument for «unnamed-symbol»"。可以通过为 bool
参数添加名称来修复:
template<class T, bool f>
template<bool _f, typename>
void S<T, f>::reset() { }
此名称应与声明中的名称一致。
所以我一直在编写自己的 unique_ptr class 并且我必须以与处理其他类型不同的方式处理数组。
template <typename TYPE, bool _arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//some methods
void reset();
};
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, _arr>::reset()
{
//some code...
}
问题是我希望重置方法仅适用于非数组分配,当使用 std::enable_if 时我收到错误:"A default template argument cannot be specified on the declaration of a member of a class template outside of its class" 尽管代码仍在编译
template<typename TYPE ,bool _arr>
class scoped_ptr final {
public:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE ,bool _arr>
template<typename = typename std::enable_if<!_arr>::type>
inline void scoped_ptr<TYPE, _arr>::reset()
{
}
我也试过这个,但是也报错:"template argument list must match parameter list"
template<typename TYPE ,bool _arr>
inline void scoped_ptr<TYPE, false>::reset()
{
}
有没有人知道如何为数组禁用此方法?我知道我可以专门化 class scoped_ptr 但我想避免代码重复。有什么办法吗?
编辑:
阅读回复后,我将代码更改为:
template <typename TYPE, bool is_arr = std::is_array<TYPE>::value>
class scoped_ptr final {
private:
typedef std::remove_extent_t<TYPE> gen;
gen* m_data;
public:
//Some methods
template<bool _arr = is_arr, typename = typename std::enable_if<!_arr>::type>
void reset();
};
template<typename TYPE, bool is_arr>
template<bool, typename>
inline void scoped_ptr<TYPE, is_arr>::reset()
{
}
代码编译没有错误,直到我尝试调用方法:
int main() {
scoped_ptr<int> ptr = new int;
ptr.reset();
}
那是我收到错误的时候:"void scoped_ptr«int,false»::reset(void): could not deduce template argument for «unnamed-symbol»"
但是如果我在 class 中编写实现,错误就会消失。我该如何解决这个问题?
如果你想让 reset()
SFINAE 友好,请将其设为假模板:
template<bool is_arr = _arr, typename = std::enable_if_t<is_arr>>
void reset();
请注意,SFINAE 在实例化模板时起作用,条件应取决于模板参数。这不是有效的 SFINAE 结构:
template<typename = typename std::enable_if<!_arr>::type>
void reset();
如果您不关心 SFINAE 的友好性,请在 reset()
中使用 static_assert()
。
编辑.
考虑以下 simple code 作为有效和无效 SFINAE 的演示:
template<class T, bool f = std::is_integral_v<T>>
struct S {
// template<typename = std::enable_if_t<f>> // (invalid)
template<bool _f = f, typename = std::enable_if_t<_f>> // (valid)
void reset() {}
};
template<class T, typename = void>
struct has_reset : std::false_type {};
template<class T>
struct has_reset<T, std::void_t<decltype(std::declval<T>().reset())>> : std::true_type {};
void foo() {
has_reset<S<int>>::value;
has_reset<S<void>>::value;
}
如果将 (valid)
行替换为 (invalid)
行,它将无法编译。
编辑 2.
在class外定义成员函数时,不重复模板参数的默认值:
template<class T, bool f>
template<bool, typename>
void S<T, f>::reset() { }
编辑 3.
出于某种原因(我想是编译器错误)MSVC 拒绝了这个定义并出现错误:"Could not deduce template argument for «unnamed-symbol»"。可以通过为 bool
参数添加名称来修复:
template<class T, bool f>
template<bool _f, typename>
void S<T, f>::reset() { }
此名称应与声明中的名称一致。