2

(従来の) ポインター型のみで実行したいサニタイズ関数があります。

私の問題は、関数をポインターのみに制限する限り取得できる関数テンプレートにありますが、関数ポインターと通常のポインターのキャスト規則の違いにより、問題が発生します。

関数は多数の型に対して実行する必要があり、そのSanitize()うちのいくつかはポインターであり、サニタイズする必要があり、その他はさまざまなアリティとパラメーター型の関数ポインターであり、サニタイズする必要がなく、そのうちのいくつかは非ポインター データです。サニタイズしてはいけないタイプ。

私が見逃している明らかなものはありますか?

  template<typename T>
  T* Sanitize(T* value)
  {
     return (T*)SanitizePointer(value);  //SanitizePointer returns void*, so cast is necessary
  }

  template<typename T>
  T Sanitize(T value)
  {
     return value;  //Non-pointers can be passed without sanitization
  }

  int main()
  {

     int  a;
     int* b;
     int (*c)();

     Sanitize(a);
     Sanitize(b);
     Sanitize(c);   //<- ERROR

     return 0;
  }
4

5 に答える 5

4

この問題は手動で解決できますが、Boosts の型特性とSFINAEヘルパーを利用しT*て、関数ポインターの場合はポインターのオーバーロードを選択的に無効にするのが最も簡単です。

template<typename T>
typename boost::disable_if<boost::is_function<T>, T*>::type
Sanitize(T* value)
{
    // ...
}
于 2009-11-25T05:50:28.267 に答える
2

これはどう?Comeau C/C++ を使用してオンラインでテスト済み。

void* SanitizePointer( void* p ) 
{ return p; }

void _Sanitize( ... ) 
{
}

void _Sanitize( void* p )
{
    SanitizePointer( p );
}

// making this a ref so as to avoid the copy, YMMV
template<typename T>  
T& Sanitize(T& value) 
{     
    _Sanitize(value);
    return value;
}  

int main(int argc, char* argv[])
{
    int  a;
    int* b;
    int (*c)();
    Sanitize(a);
    Sanitize(b);
    Sanitize(c);
    return 0;
}
于 2009-11-25T11:00:41.657 に答える
0

g ++で同様の問題に遭遇しました。私は標準的な方法で解決しましたが、可能な関数シグネチャは知っていました。私がしたことは、可能性のある関数ポインターのテンプレートの特殊化を作成したことです。

#include <cxxabi.h>
#include <iostream>
using std::cout;
using std::endl;
...

#define O cout << __PRETTY_FUNCTION__ << endl;

// Return the user-readable type name
//#if defined(__GNUC__) || defined(__GNUG__)
#define _TYPENAME(x) typeid(x).name()
#define TYPENAME(x) abi::__cxa_demangle(_TYPENAME(x), 0, 0, 0)

// Show type information for variables and type names as well
#define OTYP(x) cout << "(" << #x << ") <" << TYPENAME(x) << ">    '" << _TYPENAME(x) << "'" << endl;
#define OVAL(x) cout << #x << " = " << x << ", <" << TYPENAME(x) << ">    '" << _TYPENAME(x) << "'" << endl;

template <class T> void typ(T o()) { O; cout << "f "; OTYP(T); } 
template <class T, class U> void typ(T o(U)) { O; cout << "F "; OTYP(T); OTYP(U); }
template <class T> void typ(T o(...)) { O; cout << "e "; OTYP(T); }

const char* testcs(const std::string& s) { return s.c_str(); }
void testv(const std::string& s) { }    
void testvv() {}
void testvV(void) {}                                                            
void teste(...) { }

int main() {
  typ(testcs);
  typ(testv);
  typ(testvv);
  typ(testvV);
  typ(teste);
}

出力:

void typ(T (*)(U)) [with T = const char*, U = const std::string&]
F (T) <char const*>    'PKc'
(U) <std::string>    'Ss'

void typ(T (*)(U)) [with T = void, U = const std::string&]
F (T) <void>    'v'
(U) <std::string>    'Ss'

void typ(T (*)()) [with T = void]
f (T) <void>    'v'

void typ(T (*)()) [with T = void]
f (T) <void>    'v'

void typ(T (*)(...)) [with T = void]
e (T) <void>    'v'

お役に立てれば幸いです...

于 2014-03-20T16:32:50.013 に答える
0

説明として:関数テンプレートの部分的な特殊化を作成しようとしています。C++ はそれを許可していません。部分的な特殊化は、クラス テンプレートに対してのみ存在します。

gf が解決策を投稿しました: SFINAE を使用します (できれば Boost 経由)。

于 2009-11-25T08:15:10.723 に答える
0

何か不足していますか?次のコードは正常にコンパイルされます (VS2008 上)

void* SanitizePointer(void* value)
{
    return (void*)0;
}

template<typename T>
  T* Sanitize(T* value)
  {
     return (T*)SanitizePointer(value);  //SanitizePointer returns void*, so cast is necessary
  }

  template<typename T>
  T Sanitize(T value)
  {
     return value;  //Non-pointers can be passed without sanitization
  }

  int main()
  {

     int  a;
     int* b;
     int (*c)();

     Sanitize(a);
     Sanitize(b);
     Sanitize(c);   //<- Compiles fine

     return 0;
  }
于 2009-11-25T05:33:27.430 に答える