以下代碼來自cxx-prettyprint,它實作了檢測型別 T 是否有對應的成員
#include<iostream>
#include<vector>
#include<type_traits>
using namespace std;
struct sfinae_base
{
using yes = char;
using no = yes[2];
};
template <typename T>
struct has_const_iterator : private sfinae_base
{
private:
template <typename C> static yes& test(typename C::const_iterator*);
template <typename C> static no& test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
template <typename T>
struct has_begin_end : private sfinae_base
{
private:
template <typename C>
static yes& f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type*);
template <typename C> static no& f(...);
template <typename C>
static yes& g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*);
template <typename C> static no& g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
int main()
{
vector<int> sa{ 1,2,3,4,5 };
cout << has_const_iterator<vector<int>>::value;
cout<<has_begin_end<vector<int>>::beg_value;
cout << has_begin_end<vector<int>>::end_value;
return 0;
}
在線運行
一段時間后,我閱讀了別人的博客并將其更改為
#include<utility>
#include<iostream>
#include<vector>
using namespace std;
template <typename T>
struct has_const_iterator
{
private:
template <typename U>
static constexpr decltype(std::declval<U::const_iterator>(), bool()) test(int) { return true; }
template <typename U>
static constexpr bool test(...) { return false; }
public:
static const bool value = test<T>(1); //為什么這個不對?
using type = T;
};
template <typename T>
struct has_begin_end
{
private:
template <typename U>
static constexpr decltype(std::declval<U>().begin(), bool()) f(int) { return true; }
template <typename U>
static constexpr bool f(...) { return false; }
template <typename U>
static constexpr decltype(std::declval<U>().end(), bool()) g(int) { return true; }
template <typename U>
static constexpr bool g(...) { return false; }
public:
static bool const beg_value = f<T>(2);
static bool const end_value = g<T>(2);
};
int main()
{
vector<int> sa{ 1,2,3,4,5 };
cout << has_const_iterator<vector<int>>::value;
cout<<has_begin_end<vector<int>>::beg_value;
cout << has_begin_end<vector<int>>::end_value;
return 0;
}
在線運行
第一段代碼顯示 111
第二段代碼顯示 011
Snippet 2 幾個月前運行良好,但現在不行。
我的問題是,第二個有什么問題,為什么以前很好,現在卻出錯了?
補充:我找到了這個,他是什么意思introduce ODR violations?
uj5u.com熱心網友回復:
如果您強制呼叫,則has_const_iterator::test回傳的多載true(通過洗掉另一個):
#include <utility>
#include <vector>
#include <iostream>
template <typename T>
struct has_const_iterator
{
private:
template <typename U>
static constexpr decltype(std::declval<U::const_iterator>(), bool()) test(int) { return true; }
//template <typename U>
//static constexpr bool test(...) { return false; }
public:
static const bool value = test<T>(1);
};
int main()
{
std::cout << has_const_iterator<std::vector<int>>::value;
}
然后您會收到此錯誤訊息(或多或少):
錯誤:從屬名稱 'U::const_iterator' 被決議為非型別,但實體化會產生一個型別
注意:如果是指型別,請說 'typename U::const_iterator'
它準確地告訴你出了什么問題:typenameis missing before U::const_iterator。原因是它U::const_iterator是一個依賴名稱(它可以是型別或變數,例如,取決于U確切的內容),因此您需要指定它參考一個型別。
請注意,以前的版本確實使用typename:
template <typename C> static yes& test(typename C::const_iterator*);
//-------------------------------------^^^^^^^^
此版本有效:
#include <utility>
#include <vector>
#include <iostream>
template <typename T>
struct has_const_iterator
{
private:
template <typename U>
static constexpr decltype(std::declval<typename U::const_iterator>(), bool()) test(int) { return true; }
template <typename U>
static constexpr bool test(...) { return false; }
public:
static const bool value = test<T>(1);
};
int main()
{
std::cout << has_const_iterator<std::vector<int>>::value;
}
演示
uj5u.com熱心網友回復:
您缺少 atypename因為U::const_iterator是從屬名稱。
template <typename T>
struct has_const_iterator
{
private:
template <typename U>
static constexpr decltype(std::declval<typename U::const_iterator>(), bool()) test(int) { return true; }
// ^^
template <typename U>
static constexpr bool test(...) { return false; }
public:
static const bool value = test<T>(1); //為什么這個不對?
using type = T;
};
修復后列印預期結果:https ://godbolt.org/z/jP9G95Pb1l 。
不過,我還沒有找到產生沒有型別名的輸出的編譯器111。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/524124.html
標籤:C c 11模板
下一篇:如何呼叫回傳函式指標的函式?
