次のコードでは、比較的シンプルな型消去技術を使用しています。クラスinterpreter_context_ptr
は「インタフェース」を定義し、インタフェースを実装するオブジェクトへのポインタを使用してinterpreter_context_ptr
を構築することができます。これにより、仮想ディスパッチを使用せずに多形性が可能になります。型消去、デリゲート、およびラムダ関数(msvc)
これは、Impossibly Fast Delegatesという古い記事と非常に似ています。また、githubのbadairでeraserfaceプロジェクトをチェックしてください。
また、初めて認識しない場合、+[](...)
の構文は、いわゆる「ポジティブラムダ」構文です。hereは良い説明です。ここで
はMCVEです:テスト中の
#include <iostream>
#include <string>
#include <vector>
class interpreter_context_ptr {
void * object_;
void (*new_text_call_)(void *, const std::string &);
void (*error_text_call_)(void *, const std::string &);
void (*clear_input_call_)(void *);
public:
void new_text(const std::string & str) const {
this->new_text_call_(object_, str);
}
void error_text(const std::string & str) const {
this->error_text_call_(object_, str);
}
void clear_input() const { this->clear_input_call_(object_); }
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_(+[](void * o, const std::string & str) {
static_cast<T *>(o)->new_text(str);
})
, error_text_call_(+[](void * o, const std::string & str) {
static_cast<T *>(o)->error_text(str);
})
, clear_input_call_(+[](void * o) { static_cast<T *>(o)->clear_input(); }) {
}
};
/***
* Tests
*/
struct A {
void new_text(const std::string & str) {
std::cout << "A: " << str << std::endl;
}
void error_text(const std::string & str) {
std::cout << "A! " << str << std::endl;
}
void clear_input() { std::cout << std::endl; }
};
struct B {
void new_text(const std::string & str) {
std::cout << "B: " << str << std::endl;
}
void error_text(const std::string & str) {
std::cout << "B! " << str << std::endl;
}
void clear_input() { std::cout << std::endl; }
};
int main() {
std::vector<interpreter_context_ptr> stack;
A a;
B b;
stack.emplace_back(&a);
stack.back().new_text("1");
stack.emplace_back(&b);
stack.back().new_text("2");
stack.emplace_back(&b);
stack.back().new_text("3");
stack.back().clear_input();
stack.pop_back();
stack.back().error_text("4");
stack.emplace_back(&a);
stack.back().error_text("5");
stack.pop_back();
stack.back().error_text("6");
stack.pop_back();
stack.back().new_text("7");
stack.back().clear_input();
stack.pop_back();
std::cout << "Stack size = " << stack.size() << std::endl;
}
コードは、わずか数行非常に簡単で、私は最後の数ヶ月で作業したプロジェクトで、gccと打ち鳴らすに適しています。
しかし私は理解していないMSVCから非常に簡潔なエラーメッセージを受け取ります。
最初に、それは正のラムダについて文句を言っていますが、私はそうすべきではないと思います。
Error(s):
source_file.cpp(27): error C2061: syntax error: identifier 'T'
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(655): note: see reference to function template instantiation 'interpreter_context_ptr::interpreter_context_ptr<A>(T *)' being compiled
with
[
T=A
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(918): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(917): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(929): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(928): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(28): error C2593: 'operator +' is ambiguous
source_file.cpp(28): note: could be 'built-in C++ operator+(void (__cdecl *)(void *,const std::string &))'
source_file.cpp(28): note: or 'built-in C++ operator+(void (__stdcall *)(void *,const std::string &))'
source_file.cpp(28): note: or 'built-in C++ operator+(void (__fastcall *)(void *,const std::string &))'
source_file.cpp(28): note: or 'built-in C++ operator+(void (__vectorcall *)(void *,const std::string &))'
source_file.cpp(28): note: while trying to match the argument list '(interpreter_context_ptr::<lambda_3268dba1ab087602b708c8fa2c92932b>)'
source_file.cpp(30): error C2061: syntax error: identifier 'T'
source_file.cpp(31): error C2593: 'operator +' is ambiguous
source_file.cpp(31): note: could be 'built-in C++ operator+(void (__cdecl *)(void *,const std::string &))'
source_file.cpp(31): note: or 'built-in C++ operator+(void (__stdcall *)(void *,const std::string &))'
source_file.cpp(31): note: or 'built-in C++ operator+(void (__fastcall *)(void *,const std::string &))'
source_file.cpp(31): note: or 'built-in C++ operator+(void (__vectorcall *)(void *,const std::string &))'
source_file.cpp(31): note: while trying to match the argument list '(interpreter_context_ptr::<lambda_b251fc93653023678ada88e17e2a71b3>)'
source_file.cpp(32): error C2061: syntax error: identifier 'T'
source_file.cpp(32): error C2593: 'operator +' is ambiguous
source_file.cpp(32): note: could be 'built-in C++ operator+(void (__cdecl *)(void *))'
source_file.cpp(32): note: or 'built-in C++ operator+(void (__stdcall *)(void *))'
source_file.cpp(32): note: or 'built-in C++ operator+(void (__fastcall *)(void *))'
source_file.cpp(32): note: or 'built-in C++ operator+(void (__vectorcall *)(void *))'
source_file.cpp(32): note: while trying to match the argument list '(interpreter_context_ptr::<lambda_3ba87b1970191b4772ddfa67a05f70ea>)'
source_file.cpp(28): error C2088: '+': illegal for class
source_file.cpp(31): error C2088: '+': illegal for class
source_file.cpp(32): error C2088: '+': illegal for class
さて、何かがラムダは、暗黙的に関数ポインタに変換され、単項operator +
がありますここで、マイクロソフトの土地で「正ラムダ」理論、と間違っているのです(私はrextester.comから、これらのエラーを貼り付けています)ノーオペレーション。それはいいです、正のラムダを取り除きましょう。
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_([](void * o, const std::string & str) {
static_cast<T *>(o)->new_text(str);
})
, error_text_call_([](void * o, const std::string & str) {
static_cast<T *>(o)->error_text(str);
})
, clear_input_call_([](void * o) { static_cast<T *>(o)->clear_input(); }) {
}
MSVCはまだ幸せではない判明 - 主なエラーが不可解C2061です。
コンパイラは、予想されなかった識別子を見つけました。それを使用する前に識別子が宣言されていることを確認してください。
初期化子は、かっこで囲むことができます。この問題を回避するには、宣言子をかっこで囲むか、typedefにします。
このエラーは、コンパイラが式をクラステンプレートの引数として検出した場合にも発生する可能性があります。 typenameを使用してコンパイラに型を伝えます。ここで
は完全なログです:
Error(s):
source_file.cpp(27): error C2061: syntax error: identifier 'T'
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(655): note: see reference to function template instantiation 'interpreter_context_ptr::interpreter_context_ptr<A>(T *)' being compiled
with
[
T=A
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(918): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(917): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(929): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(928): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(30): error C2061: syntax error: identifier 'T'
source_file.cpp(32): error C2061: syntax error: identifier 'T'
私はT
年代の前にどこにでもtypename
を入れての彼らの提案をしようと、それは何も解決しない、と私はより多くの有益なエラーメッセージを得ることはありません。
ここには何がありますか?ここでC2061の "識別子"エラーが意味することは、MSVCがラムダ本体の内部のテンプレートパラメータを追跡できないこと、またはそれを間違って解析していることを意味し、T
は変数であり型ではないと思いますか?
このMSVC 2015のようなテンプレート関数内にあるラムダ内のテンプレートパラメータを参照することはできませんか?
ラムダを除外して静的なテンプレート関数を作成するだけでいいですか?
それは私がちょうど完全にラムダを取り除くなどのようなテンプレート関数を使用して取得した場合、その後、MSVCは罰金それをコンパイルすることが判明:
class interpreter_context_ptr {
void * object_;
void (*new_text_call_)(void *, const std::string &);
void (*error_text_call_)(void *, const std::string &);
void (*clear_input_call_)(void *);
template <typename T>
struct helper {
static void new_text(void * o, const std::string & str) {
static_cast<T*>(o)->new_text(str);
}
static void error_text(void * o, const std::string & str) {
static_cast<T*>(o)->error_text(str);
}
static void clear_input(void * o) {
static_cast<T*>(o)->clear_input();
}
};
public:
void new_text(const std::string & str) const {
this->new_text_call_(object_, str);
}
void error_text(const std::string & str) const {
this->error_text_call_(object_, str);
}
void clear_input() const { this->clear_input_call_(object_); }
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_(&helper<T>::new_text)
, error_text_call_(&helper<T>::error_text)
, clear_input_call_(&helper<T>::clear_input) {
}
};
をしかし、私はコメントで書いたように、私は」私は実際にこれを遠くに行かなければならないとかなり驚きました。 MSVCの開発者は、this C++11 feature pageにラムダ関数を完全にサポートし実装していると主張しています。私はラムダの範囲で周囲のテンプレートパラメータを参照できることを含むべきだと思います。
あなたはClan/C2コンパイラフロントエンドに付属しているVS2015を使用しています。 MSVCによってスローされたエラーメッセージを理解できない場合は、別のコンパイラを試してみてください。 MSVCはそうではないが、Clangはこのコードを受け入れるかもしれないことに注意してください。それから、あなたは運がない。しかし、そうでない場合には、どんな場合でも明確なエラーメッセージが表示されます。 – rubenvb
Harm、残念ながら、少なくともClangとGCCは警告なしでこのコードを受け入れているようですので、Clang/C2はMicrosoft C++ライブラリを使用していますが、エラーの原因になる可能性があります。この場合、ライブラリのバグです。 – rubenvb
また、ラムダから '+'を削除してみてください。私はそのコンストラクトのMSVCチョークの前に読んでいます。コードはコンパイルされずにコンパイルされますが、動作は同じであることを確認してください。 – rubenvb