ライブラリで const および非 const テンプレート引数の関数を提供しようとすると、奇妙な問題に遭遇しました。次のソース コードは最小限の現象の例です。
#include <iostream>
template<typename some_type>
struct some_meta_class;
template<>
struct some_meta_class<int>
{
typedef void type;
};
template<typename some_type>
struct return_type
{
typedef typename some_meta_class< some_type >::type test;
typedef void type;
};
template<typename type>
typename return_type<type>::type foo( type & in )
{
std::cout << "non-const" << std::endl;
}
template<typename type>
void foo( type const & in )
{
std::cout << "const" << std::endl;
}
int main()
{
int i;
int const & ciref = i;
foo(ciref);
}
非 const バージョンと foo の const バージョンを実装しようとしましたが、残念ながらこのコードは CLANG 3.0 と gcc 4.6.3 ではコンパイルできません。
main.cpp:18:22: エラー: 未定義のテンプレート 'some_meta_class' の暗黙的なインスタンス化
そのため、何らかの理由で、コンパイラは const int 参照に foo の非 const バージョンを使用したいと考えています。some_meta_class の実装がないため、これは明らかに上記のエラーにつながります。奇妙なことに、次の変更のいずれかを行うと、コードが正常にコンパイルされて機能します。
- 非constバージョンのコメントを外す/削除する
- return_type::test の typedef を uncomemnt/削除します
もちろん、この例は最小限であり、純粋に学術的なものです。私のライブラリでは、const バージョンと非 const バージョンが異なる型を返すため、この問題に遭遇しました。部分的に特殊化されたヘルパー クラスを使用して、この問題を管理しました。
しかし、なぜ上記の例でこのような奇妙な動作が発生するのでしょうか? コンパイラは、const バージョンが有効であり、よりよく一致する非 const バージョンを使用したくないのはなぜですか?