テンプレート機能があります。引数がポインター型でない限り、セマンティクスが明確に定義されています。誰かがポインタ型の引数を渡してこの関数を呼び出した場合、コンパイル時のエラーを強制したいと思います。一般的な (合法的な) テンプレートと、対応する部分的に特殊化された (違法な) バージョンを問題なく作成できます。関数定義から関数呼び出しまでエラーを延期する方法がわかりません。
4 に答える
C++0x の使用: ( http://ideone.com/ZMNb1でライブを参照)
#include <type_traits>
#include <iostream>
template <typename T>
void cannot_take_pointer(T ptr)
{
static_assert(!std::is_pointer<T>::value,
"cannot_take_pointer requires non-pointer argument");
std::cout << "ok\n";
}
int main()
{
int x;
cannot_take_pointer(x);
cannot_take_pointer(&x); // fails to compile
}
実際、それを専門化する必要はありません。これを関数本体に追加するだけです:
BOOST_STATIC_ASSERT(!boost::is_pointer<T>()::value);
これにより、かなり理解しやすいはずの障害が発生します。
(BOOST_STATIC _ASSERT のようなものを使用する代わりに) 自分でこれを行いたい場合は、通常必要な 2 つまたは 3 つの基本的なトリックがあります。
最初の (そしておそらくあなたの場合は最も重要な) は、コンパイル時に実行されるものを何も生成せずにコンパイルされたコードを取得するために (通常sizeof
は結果を にキャストして) を使用することです。void
2 つ目は、適切な状況下では違法なコードを生成することです。典型的な方法の 1 つは、ある式の値と同じサイズの配列を作成することです。式の値が 0 の場合、配列のサイズは 0 になりますが、これは許可されていません。または、サイズが 1 の場合は合法です。それに関する1つの問題は、それが生成するエラーメッセージが通常かなり無意味であることです.「エラー:配列には正のサイズが必要です」(またはそのようなもの)が「テンプレートパラメータはポインタであってはならない」にどのように関連するかを推測するのは難しいです. .
より意味のあるエラー メッセージを生成するには、通常、少し異なる方法を使用します。この場合、あるクラスから別のクラスへの変換は、式が false の場合は失敗しますが、true の場合は成功します。これを行う1つの方法は次のとおりです。
template <bool>
struct check { check(...); };
template <>
class check<false> {};
これは、 (理論的には) 他の型を に変換できることcheck(...);
を意味します(ただし、関数を宣言するだけで、決して定義しないことに注意してください。したがって、そのようなコードを実行しようとしても、リンクされません)。変換コンストラクターがないということは、他のものを に変換しようとすることを意味し、常に失敗します。check<true>
check<false>
check<false>
次に、次のようなマクロでそれを使用できます。
#define STATIC_ASSERT(expr, msg) { \
struct Error_##msg {}; \
(void)sizeof(check<(expr)!=0>((Error_##msg))); \
}
これは次のように使用しますSTATIC_ASSERT(whatever, parameter_cannot_be_a_pointer);
。それは次のように展開されます:
struct Error_parameter_cannot_be_a_pointer {};
(void)sizeof(check<(expr)!=0>(Error_parameter_cannot_be_a_pointer);
次に、expr
!= 0 の場合、Error_parameter_cannot_be_a_pointer を に変換しようとしますがcheck<true>
、これは成功します。
一方、 do が 0 の場合expr
、に変換しようとしますが、check<false>
失敗します。少なくとも、それが発生したときに、次のようなエラー メッセージが表示されることを願っています。
error cannot convert:
Error_parameter_cannot_be_a_pointer
to
check<false>
明らかに、できればそれよりもさらに優れたメッセージが必要ですが、現状でも、それはそれほどひどいことではありません. 「ラッピング」を無視し、ソースタイプの名前を見て、問題のかなりのアイデアを得る必要があります。
の完璧なケースのように聞こえboost::disable_if
ます。このようなものがうまくいくはずです。
template <class T>
void func(T x, typename boost::disable_if<boost::is_pointer<T> >::type* dummy = 0) {
std::cout << x << std::endl;
}
func(10); // works
func(std::string("hello")); // works
func("hello world"); // error: no matching function for call to 'func(const char [6])'
func(new int(10)); // error: no matching function for call to 'func(int*&)'