'using'声明为SFINAE
'using' declaration as SFINAE
我可以在从模板类私有派生时使用SFINAE(或其他技术)进行using
声明吗?为了更好地理解,请参阅下面的代码:
#include <iostream>
struct S1 {
void f() { std::cout << "S1::fn"; }
};
struct S2 {
void f() { std::cout << "S2::fn"; }
void g() { std::cout << "S2::gn"; }
};
template <class T>
struct D : private T {
using T::f;
// using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // fail. But wants to be ok and prints 'S2::g'
return 0;
}
我怎样才能达到期望的行为(如果可能的话)?
Bryan Chen的答案的一个变体看起来更丑陋,但更容易扩展到多个检查,并且不需要复制D<type-with-f>
和D<type-without-f>
之间共享的代码,是使用继承链,其中每个步骤检查一个额外的成员。唯一需要的重复是继承构造函数(如果适用)。
struct A {
void f() { }
void g() { }
void i() { }
};
// The generic case. D<T, char[N]> simply provides what D<T, char[N+1]> provides.
template <typename T, typename U = char[1]>
struct D : D<T, char[sizeof(U) + 1]> {
using D<T, char[sizeof(U) + 1]>::D;
};
// The end of the chain. This is where T gets inherited. It declares all of its own
// specialisations as its friends, so that they can access other members of T.
template <typename T>
struct D<T, char[6]> : private T {
template <typename, typename>
friend struct D;
D(int) { }
void fun() { }
};
// Check for T::f.
template <typename T>
struct D<T, char[2 + !sizeof(&T::f)]> : D<T, char[3]> {
using D<T, char[3]>::D;
using T::f;
};
// Check for T::g.
template <typename T>
struct D<T, char[3 + !sizeof(&T::g)]> : D<T, char[4]> {
using D<T, char[4]>::D;
using T::g;
};
// Check for T::h.
template <typename T>
struct D<T, char[4 + !sizeof(&T::h)]> : D<T, char[5]> {
using D<T, char[5]>::D;
using T::h;
};
// Check for T::i.
template <typename T>
struct D<T, char[5 + !sizeof(&T::i)]> : D<T, char[6]> {
using D<T, char[6]>::D;
using T::i;
};
int main() {
D<A> d = 4; // ok: verify that constructors got inherited
// A &a = d; // error: verify that inheritance of A is private
d.f(); // ok: verify that f got inherited
d.g(); // ok: verify that g got inherited
// d.h(); // error: verify that h is not available
d.i(); // ok: verify that i got inherited
d.fun(); // ok: verify that the inheritance chain didn't get broken
}
注意:与其检查&T::f
,不如改为对std::declval<T>().f()
执行某些操作。前者无法处理重载函数。
C++部分模板专用化和使用 SFINAE 的decltype(void(&T::g))
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::fn"; }
};
struct S2 {
void f() { std::cout << "S2::fn"; }
void g() { std::cout << "S2::gn"; }
};
template <class T, class V = void>
struct D : private T {
using T::f;
};
template <class T>
struct D<T, decltype(void(&T::g))> : private T {
using T::f;
using T::g; // need this only if T provides g() function
};
int main() {
D<S1>().f(); // ok. Prints 'S1::f'
D<S2>().f(); // ok. Prints 'S2::f'
D<S2>().g(); // ok. Prints 'S2::g'
return 0;
}
现场演示
编辑:
这是另一种更灵活的方法,但我不知道private virtual
继承如何在实际用例中工作。如果它可能导致任何问题(例如 UB),请告诉我。
#include <iostream>
#include <type_traits>
struct S1 {
void f() { std::cout << "S1::fn"; }
};
struct S2 {
void f() { std::cout << "S2::fn"; }
void g() { std::cout << "S2::gn"; }
};
struct S3 {
void g() { std::cout << "S3::gn"; }
};
template <class T, class = void>
struct D_f {};
template <class T>
struct D_f<T, decltype(void(&T::f))> : private virtual T {
using T::f;
};
template <class T, class = void>
struct D_g {};
template <class T>
struct D_g<T, decltype(void(&T::g))> : private virtual T {
using T::g;
};
template <class T>
struct D : D_f<T>, D_g<T> {
};
int main() {
D<S1>().f();
D<S2>().f();
D<S2>().g();
D<S3>().g();
return 0;
}
现场演示
相关文章:
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- "using namespace std;"在C++的作用是什么?
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 提供与TMP和SFINAE的通用接口
- "Inverse SFINAE"避免模棱两可的过载
- vector<vector<double>> to mxArray using memcpy
- Using C++ CryptAPI:CNG Create CSR
- STLPort using C++11
- 函数中的 c++ using 语句,后跟函数名称(对于 ADL?
- Using getchar_unlocked()
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如何在儿童类中使用SFINAE
- 使用 SFINAE 作为模板参数的编译时递归
- 嵌套命名空间的"using"指令,但需要命名内部命名空间
- 为什么"using System;"不被视为不良做法?
- 'using'声明为SFINAE