如果要进行类型检查,请启用非模板成员函数

时间:2012-10-24 04:26:35

标签: c++ templates c++11

例如

template <class T1, class T2>
class foo
{
    T1 t1;
    T2 t2;

    T1 bar(); //Always exists
    decltype(t1(t2)) baz(); //Should only exist if t1(t2) is valid
};

如果baz无效,我仍然希望只要没有人实际调用baz就编译该程序。

1 个答案:

答案 0 :(得分:4)

你可以使baz成为一个模板,这样如果返回类型无效,那么成员将是SFINAE-d out而不是导致硬错误:

template <class T1, class T2>
class foo
{
    T1 t1;
    T2 t2;

    T1 bar(); //Always exists

    template<typename T = T1>
    decltype(std::declval<T&>()(t2)) baz();
};

T参数是使计算表达式依赖于类型所必需的,否则SFINAE不适用。如果您担心此实施细节“泄露”并且某人可能会尝试f.baz<int>(),您可以使用baz声明template<typename... Dummy, typename T = T1>并强制使用例如static_assert( sizeof...(Dummy) == 0, "Incorrect usage" );。函数体中的&foo<T, U>::baz<>。这两种方法确实使得更难以获取成员的地址:它应该看起来像例如template<typename...> struct void_ { using type = void; }; template<typename T1, typename T2, typename = void> class foo { // version without baz }; template<typename T1, typename T2> class foo<T1, T2, typename void_<decltype(std::declval<T1&>()(std::declval<T2>()))>::type> { decltype(std::declval<T1&>()(std::declval<T2>())) baz(); };

另一种方法是引入类模板特化:

&foo<T, U>::baz

在这种情况下,foo可以获取成员的地址(假设它当然存在)。两个专业化共同的代码可以在一个公共基础中被考虑在内,并且如果担心作为实现细节引入的附加模板参数可能泄漏,则可能具有“真实”{{1}}只接受两个模板参数,继承自这样的实现。