![](/img/trans.png)
[英]C++11 - enable_if - function implementation outside of class definition
[英]function implementation with enable_if outside of class definition
所以基本上,我现在有一个非常基本的泛型类,目前正在测试type_traits头。 我目前正在尝试使用某些类型的函数,即现在的算术类型。
#include <type_traits>
template <typename T> class Test {
public:
template <typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
该函数完美地工作,仅适用于算术类型。
但我喜欢保持我的课程整洁,只让他们有原型,而功能实现在课堂之外。
使用标准模板即
void test();
template <typename T> void Test<T>::test() {}
这很简单,我知道怎么做,但是我不知道如何用“ std::enable_if
”在类之外声明实现,并且我在编译过程中所做的每一次尝试都说原型与之中的任何一个都不匹配类。
我设法在这里找到了一个类似的问题 ,但那里的课程是标准的而不是通用的。
PS。 我使用MinGW-w64和-std = c ++ 17
您需要一组模板参数用于类模板,一组单独的模板参数用于成员函数模板。 您需要重复整个复杂的返回类型,因为它是函数模板签名的一部分。 请注意,您不能重复默认参数=T
,否则编译器会认为您尝试定义它两次(不检查新定义是否相同)。
template <typename T> template <typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type
Test<T>::print()
{
// Implementation here.
}
顺便说一下,你正在使用编写类型的“漫长道路”,正如C ++ 11中所需要的那样。 但是C ++ 14引入了一个std::enable_if_t
快捷方式,而C ++ 17引入了一个std::is_arithmetic_v
快捷方式。 因此,如果您使用的是C ++ 17,您也可以编写类型
typename std::enable_if<std::is_arithmetic<U>::value>::type
就像
std::enable_if_t<std::is_arithmetic_v<U>>
你可以试试
template <typename T>
template <typename U>
std::enable_if_t<std::is_arithmetic<U>::value> Test<T>::print()
{ /* do something */ }
以下是一个完整的工作示例
#include <iostream>
#include <type_traits>
template <typename T> class Test
{
public:
template <typename U = T>
std::enable_if_t<std::is_arithmetic<U>::value> print();
};
template <typename T>
template <typename U>
std::enable_if_t<std::is_arithmetic<U>::value> Test<T>::print()
{ std::cout << "test!" << std::endl; }
int main ()
{
Test<int> ti;
Test<void> tv;
ti.print(); // compile
//tv.print(); // compilation error
}
关闭主题1
注意,您的解决方案可以通过这种方式被劫持
Test<void>{}.print<int>();
为了避免这个问题你可以强加T
等于U
,
template <typename T> class Test
{
public:
template <typename U = T>
std::enable_if_t< std::is_arithmetic<U>::value
&& std::is_same<T, U>::value> print()
{ }
};
关闭主题2
如您所见,您必须重复SFINAE部分( std::enable_if_t
, std::is_arithmetic
和std::is_same
)。
考虑到你必须在头文件中重复执行,我不认为(恕我直言)认为在类的主体之外编写模板类的实现是一个好主意。
既然你还没有发布你尝试的内容,我无法告诉你哪里出错了。 但是这就是你如何在类定义之外实现成员函数(虽然它仍然需要在头文件中实现 ,所以我认为这不值得麻烦)
template <typename T> class Test {
public:
template <typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
template <typename T> // class template parameter
template <typename U> // function template parameter
inline typename std::enable_if<std::is_arithmetic<U>::value>::type Test<T>::print()
{
}
如果你把enable_if
放在默认的模板参数中,无论如何都是这样,那么类外定义会变得容易一些:
template<typename T>
struct Test
{
template <typename S = T
, typename = typename std::enable_if<std::is_arithmetic<S>::value>::type >
void print();
};
template<typename T>
template<typename S, typename>
void Test<T>::print()
{
//some code
}
如果您需要额外的模板参数U,正如其他答案所解释的那样,正确的语法是
template<typename T>
struct test
{
template<typename U>
... a_method(...);
};
template<typename T>
template<typename U>
... test<T>::a_method(...)
{
...
}
然而,在你的特殊情况下,如果你只需要检查T
型的某些属性,这实际上是一个额外的复杂功能。 U
型的引入是“人为的”,仅仅因为SFINAE而在这里
恕我直言, if constexpr
使用它更优雅,更简单
#include <iostream>
#include <type_traits>
template <typename T>
class Test
{
public:
void print();
};
template <typename T>
void Test<T>::print()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "\nOk T is arithmetic";
// ... your implementation here ...
}
else
{
// throw an exception or do what ever you want,
// here a compile-time error
static_assert(!std::is_same_v<T, T>, "not implemented yet...");
}
}
main()
{
Test<int> t;
t.print();
Test<void> t2;
// t2.print(); <- will generate a compile time error
}
template<typename T>
struct test
{
template<typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
template<typename T> template<typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type test<T>::print()
{
}
void foo()
{
test<int> t;
t.print();
test<void*> u;
u.print();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.