基本上,我现在有一个非常基本的泛型类,目前正在测试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() {}
这很简单,我知道怎么做,但我不知道如何用&#34; std::enable_if
&#34;在类之外声明实现。在编译过程中,我所做的每一次尝试都表明原型与类中的任何原型都不匹配。
我设法在这里找到了类似的question,但那里的类是标准的而不是通用的。
PS。我使用MinGW-w64和-std = c ++ 17
答案 0 :(得分:6)
您需要为类模板提供一组模板参数,为成员函数模板提供一组单独的模板参数。您需要重复整个复杂的返回类型,因为它是函数模板签名的一部分。请注意,您不能重复默认参数=T
,否则编译器会认为您尝试定义它两次(不检查新定义是否相同)。
template <typename T> template <typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type
Test<T>::print()
{
// Implementation here.
}
顺便说一下,你正在使用&#34;漫长的方式&#34;编写类型,如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>>
答案 1 :(得分:4)
您可以尝试使用
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
)。
考虑到你必须在标题中重复实现,我不认为(恕我直言)在类的主体之外编写模板类的实现是一个好主意。
答案 2 :(得分:1)
由于你还没有发布你尝试的内容,我无法告诉你哪里出错了。但是这就是你如何在类定义之外实现成员函数(虽然它仍然需要implemented in the header,所以我认为这不值得麻烦)
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()
{
}
答案 3 :(得分:1)
如果你将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
}
答案 4 :(得分:0)
如果您需要额外的模板参数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
}
答案 5 :(得分:-1)
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();
}