C 如何在編譯期檢測乙個類是否有成員函式?

時間 2021-05-29 22:56:36

1樓:霧雨口口子

#include

#include

using

namespace

std;

#define GEN_MEMBER_FUNC_CHECK_CLASS(func_return_type, func_name, ...) \

struct HasMemberFuncInspector_##func_return_type##_##func_name ; \

template \

struct HasMember_##func_return_type##_##func_name : public decltype(HasMemberFuncInspector_##func_return_type##_##func_name::Check(0)){};

//test case

structA};

structB};

structC};

struct

D{};

GEN_MEMBER_FUNC_CHECK_CLASS(string

,print

,false,0

)int

main()

2樓:fairlyblank

原因應該是template申明的型別,本身不能是個模板,如果要用模板的模板,應該類似這樣的寫法:

例如要申明乙個本身是乙個帶有兩個模板型別的型別T:

template class T>

3樓:朱涵俊

如果是只考慮public成員,gcc可以用typeof

typeof (testClass::testMember) i;

4樓:暮無井見鈴

我個人認為更適合的手段還是檢測函式呼叫表示式的合法性,而非檢測成員函式的名稱。(原因後述)

比如 C++20 requires (個人想多提及一下 requires 子句可以帶引數,然而 requires 子句的引數為了和函式引數保持一致而有些不便):

template

class

...Args

>inline

constexpr

bool

callable_with_memfun_v

=// 或使用概念

requires(T

&&t,Args

&&...

args);

或者 C++11 利用 decltype 的 SFINAE :

namespace

detail

);template

, class

...>

auto

test_callable_with_memfun

(...)

->std::

false_type;}

// namespace detail

template

class

...Args

>struct

callable_with_memfun

:decltype

(detail

::test_callable_with_memfun

...>(0

)){};

// 或使用變數模板( C++14 起),編譯效果應該更好( by Casey Carter )

偏特化上的 SFINAE 看起來目前還是非標準的( CWG 2054 ),但一般編譯器都支援,而且主流標準庫實現都用到這種寫法,標準委員會也有些人直接這麼寫而未說這是非標準的。我們或許可以認為它實際上沒有移植問題。

前面已經有人給出了偏特化 SFINAE 的寫法,這裡不重複了。(我不怎麼懂古代 C++ ,暫不考慮古代 C++ 的寫法)

至於為什麼不適合……

我們知道成員函式和非成員函式類似,都能過載。

倘若類提供了 begin 的兩個版本,乙個有 const 限定而另乙個沒有( STL 容器就是這種情況),則直接用 &T::begin 取非靜態成員函式的位址存在歧義。此情況下需要把這個過載集的位址轉型( static_cast 或 C 風格轉型)成單一的成員函式指標型別(比如 T::

const_iterator (T::*)() const ),而引數列表變得無法推導了。

到這裡可以看出不對勁了。即使不論更複雜的函式模板,我們面對這個過載集,是無法窮舉每乙個潛在的引數列表的。(注意有引數列表就可以推導返回型別了,雖然寫起來仍然麻煩)

從而 C++ 中目前還是做不到檢測「是否有名為某個識別符號的成員函式」的。不過加入靜態反射的話就可以了。

而僅檢測名字而不在乎呼叫表示式的話,意義可能不是很大。雖然繼承時可能有用。

另外私有成員也會帶來問題。不過 C++20 更改了特化上的訪問檢查。此後該問題仍可規約成前面提及的「需要指定具體的函式型別」。

實現上非虛成員函式的簽名不一定要和標準描述的一致,只要過載決議選擇的過載能有標準所要求的效果就行( [member.functions]/2 )。這至少允許實現新增額外的有預設實參的引數,或者把標準描述中不是模板的成員函式改成模板(為了滿足標準的約束)。

C++20 起,取標準庫函式(除了一些 iostream 相關的直接用作操縱符的函式,譬如 std::endl )的位址的效果都變成未指定,並且可以且不通過編譯( [namespace.std]/6 )。

不難看出,標準的傾向是只保證函式呼叫表示式的合法性。(只)檢測成員函式的名稱可能不是乙個好選擇。

5樓:Ubp.a

這邊寫成這樣沒有問題,你可以考慮改寫一下

建議把函式簽名直接作為使用者需要填寫的內容,而不是【拆開成 Ret,Args...,然後在內部分成多個】

另外考慮少了,應該是 normal, const, &, &&, const&, const&&,甚至還有 volatile,總共至少也得有2*2*3=12種情況,所以拆開寫不好(另外還有靜態成員函式,假設題意要的是非靜態成員函式吧,如果考慮靜態,那麼函式簽名上要加上物件型別)

6樓:stay

template

class

= std

::void_t

<>>struct

HasToStringFunction

:false_type

{};template

T>struct

HasToStringFunction

void_t

(declval

().toString

())>>

:true_type

{};又要拿出這個萬能 std::void_t 了

C 裡,如何在乙個類廠裡,用靜態方式判斷乙個類是否繼承自某個類??

dodoleon 直接用c 11的 std is base of 就可以判斷是否是通過乙個基類繼承下來的。 Certain Y template size t m constexpr auto string equal const char value n const char o m for in...

c 中,如何判斷乙個類是否可以通過索引器取值?

當乙個類包含陣列成員時,索引器的使用將大大簡化對類中陣列成員的訪問。定義類似於屬性也具有get和set訪問器。具體定義如下 修飾符 資料型別 this 索引型別 index set 索引器可以讓我們像訪問陣列一樣訪問類中的陣列成員。簡單點來說是因為IList定義了T this int index 方...

C 如何編譯出乙個不需要作業系統的程式?

FledgeXu 如果拋棄作業系統執行編譯好的 C 程式,執行它的過程和執行乙個作業系統基本上沒什麼區別了。首先你要先寫彙編,從實模式轉化為保護模式,然後讀取硬碟特定扇面 扇區 磁軌上的32位 C 程式,載入記憶體後並執行。在編寫 C 程式的過程也有很多要注意的地方,首先你無法再使用標準庫了,因為標...