[英]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.