3

例如

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.

4

1 回答 1

4

您可以制作baz一个模板,这样如果返回类型无效,则该成员将被 SFINAE-d 淘汰,而不是导致硬错误:

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>(),您可以在函数体中声明baztemplate<typename... Dummy, typename T = T1>强制正确使用 with 。static_assert( sizeof...(Dummy) == 0, "Incorrect usage" );这两种方法确实使获取成员的地址变得更加困难:它应该看起来像 eg &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只采用两个模板参数反过来从这样的实现继承。

于 2012-10-24T05:10:15.440 回答