簡體   English   中英

MSVC指向模板參數中的重載函數

[英]MSVC pointer to overloaded function in template parameter

我已經在一個問題上至少停留了兩個星期,被我無法理解的東西所阻擋,並在SO中提出的問題並沒有真正指出真正的問題(愚蠢的我!)。 最后,我希望我在這個問題上找到了我頭痛的真正意義。

我一直在使用模板結構作為幫助程序來檢測給定類型是否具有成員方法,此模板結構如下所示:

template
<
    typename Type,
    typename Return,
    typename Parameter,
    Return (Type::*)(Parameter)
> struct W {};

struct W的主要思想是將第四個參數作為成員函數指針放到我需要使用SFINAE技巧進行測試的成員函數中, 在前一個問題中提出了一個替代方案,它幫助我理解了很多概念。已經失蹤了,但最終,它並沒有解決我的真正問題。

我正在處理的代碼片段必須在Linux和Windows平台上運行,我用於Windows的編譯器是Linux端的MSVC(Visual Stuido 2010 10.0)和gcc(Devian 4.4.5-8)。 問題是同一段代碼不能在MSVC中編譯,但它在gcc中編譯(我感到震驚,通常是相反的,因為MSVC不太標准嚴格)。

問題的根源是我的SFINAE方法在MSVC下編譯時未能檢測到方法set::insert ,為了尋找這個失敗我寫了一個簡單的測試

#include <set>

int main(int argc, char **argv)
{
    typedef std::set<int> setint;

    std::pair<setint::iterator, bool> (setint::*p_1)(const setint::value_type &) = &setint::insert;
    W<setint, std::pair<setint::iterator, bool>, const setint::value_type &, &setint::insert> w_1;

    return 0;
}

正如我之前提到的:這個示例使用gcc編譯時沒有問題,但是在使用MSVC時在w_1的聲明中給出錯誤:

error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::pair<_Ty1,_Ty2> (__thiscall std::set<_Kty>::* )(const int &)'
    with
    [
        _Ty1=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>,
        _Ty2=bool,
        _Kty=int
    ]
    None of the functions with this name in scope match the target type

創建函數指針時按預期工作,因此p_1的聲明編譯; 但與模板參數具有相同的簽名卻沒有。 這就是為什么在SFINAE的符號替換期間set::insert檢測失敗的原因。 錯誤文本cannot convert from 'overloaded-function'並不能為我提供任何有關正在發生的事情的線索(或者我無法找到任何,因為我的英語理解不佳)。

乍一看,我一直認為問題是符號替換,但如果它同時在MSVC和gcc中失敗也是有意義的。 所以現在我想知道問題是否是一些MSVC編譯器特定的做事方式。

任何關於為何在MSVC下失敗以及如何使gcc和MSVC以相同方式工作的線索?

額外的問題: std::mapstd::set提供了一個嵌套類型_Pairib作為紅黑樹的MSVC實現下的::insert方法的返回類型(或者在mapset下的任何內容),gcc中沒有等價物實施?

編輯:

在閱讀了寒冷的回答后 ,我查看了MSVC的std::set實現。

std::setstd::_Tree的派生類,它提供了我想要檢查的方法:

// class std::_Tree, file xtree in the path 'VisualStudioPath/VC/include/'
_Pairib insert(const value_type& _Val)
    {    // try to insert node with value _Val, favoring right side
    return (insert(_Val, false));
    }

這個insert方法屬於std::_Tree范圍,而不是std::set范圍,但它是公共范圍,也是一個繼承的方法,那么為什么在名稱替換期間它不可訪問?

失敗的原因是在VC stdlib中, insert實際上不是set類模板本身的成員,而是繼承的:

測試用例,

template
<
    typename Type,
    typename Return,
    typename Parameter,
    Return (Type::*)(Parameter)
> struct W {};

struct A { void foo (int); };

struct B : public A {};

int main(int argc, char **argv)
{
    void (B::*p)(int) = &B::foo;
    // W<B, void, int, &B::foo> w; // error
    W<A, void, int, &A::foo> w;

    return 0;
}

PS。 某些GCC和某些MSVC中的錯誤都是錯誤的。

但它是在公共范圍內,也是一種繼承的方法,所以我不明白為什么它不可訪問。

因為在這種情況下不允許轉換,“14.3.2。模板非類型參數[#5]”

對於指向成員函數的類型指針的非類型模板參數,如果template-argument的類型為std :: nullptr_t,則應用null成員指針轉換(4.11); 否則,不適用任何轉換 如果template-argument表示一組重載的成員函數,則從集合中選擇匹配的成員函數(13.4)。

PPS。 所以,你明確地進行轉換,瞧,你不需要關心可能的基類:

W<setint,
  std::pair<setint::iterator, bool>,
  const setint::value_type &,
  static_cast<std::pair<setint::iterator, bool> (setint::*)(const setint::value_type &)> (&setint::insert)> w_1;

根據這個問題,標准沒有定義您可以將成員函數指針帶到Standard對象的成員。

_Pairib是一個MSVC實現_Pairib當然你在GCC中找不到類似的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM