次のようなコードでキャストができず困っていたら @yaito3014 さんに教えてもらったので、メモ。
#include <stdio.h>
class Class1 {
lint value;
public:
template <typename T>
Class1(T v = 0) : value(v) {}
operator int() const { return value; }
};
class Class2 {
using T = Class1;
public:
operator T() const { return T(334); }
};
int main() {
Class2 ist1;
Class2 ist2;
if ((Class1)ist1 == (Class1)ist2) printf("Something");
return 0;
}
このコードをコンパイルすると、ist1
を Class1
にキャストする過程で template<typename T>Class1::Class1(T)
が呼ばれて、Class1::value
が初期化できないので怒られる。
ここで、次のようにするとちゃんと operator int() const
が呼ばれる。
#include <stdio.h>
class Class1 {
lint value;
public:
template <typename T, std::enable_if_t<!std::is_convertible_v<T, Class1>,
std::nullptr_t> = nullptr>
Class1(T v = 0) : value(v) {}
operator int() const { return value; }
};
class Class2 {
using T = Class1;
public:
operator T() const { return T(334); }
};
int main() {
Class2 ist1;
Class2 ist2;
if ((Class1)ist1 == (Class1)ist2) printf("Something");
return 0;
}
こうすると std::enable_if_t
で SFINAE が効くようになる。
SFINAE は同名関数のオーバーロード解決だけでなく、キャスト演算子とコンストラクタのオーバーロードでも効く。