【问题标题】:find typename of typename in template parameter在模板参数中查找类型名的类型名
【发布时间】:2015-06-10 19:52:01
【问题描述】:

我希望在 foo 从 base 派生任何内容时编译以下代码,否则会出现编译错误。我编写了类型特征类 is_Base 因为std::is_base_of 不适用于我的模板内容。我很接近。我使用static_passoff 让它工作,但我不想使用它。那么如何在没有static_passoff hack 的情况下编写 enable_if 呢?这是运行版本:http://coliru.stacked-crooked.com/a/6de5171b6d3e12ff

#include <iostream>
#include <memory>

using namespace std;

template < typename D >
class Base
{
public:
    typedef D EType;
};

template<class T>
struct is_Base
{
    using base_type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

    template<class U>
    static constexpr std::true_type test(Base<U> *) { return std::true_type(); }
    static constexpr std::false_type test(...) { return std::false_type(); }

    using value = decltype( test((T*)0) );
};

template < typename A >
using static_passoff = std::integral_constant< bool, A::value >;

template <typename T, typename = typename std::enable_if< static_passoff< typename is_Base< T >::value >::value >::type >
void foo(T const&)
{
}


class Derived : public Base<Derived> {};
class NotDerived {};


int main()
{
    Derived d;
    //NotDerived nd;

    foo(d);
    //foo(nd); // <-- Should cause compile error

    return 0;
}

【问题讨论】:

  • std::is_base_of does not work well with my ... stuff。请参阅 Scott Meyer 的“Effective Modern C++”第 27 条。您需要 std::is_base_of&lt;Base, std::decay_t&lt;T&gt;&gt;::value
  • @kfsone Base 是一个类模板。
  • 好吧,你明白我的意思。见ideone.com/d3Of8G
  • @kfsone 你不明白我的意思。 Base 是一个类模板。不是一门课。
  • @Barry 在他的代码中,我没有引用他的代码。 std::is_base_of&lt;TheBaseYouWantToTestAgainst, std::decay_t&lt;T&gt;&gt;::value。开心吗?

标签: c++ templates std typetraits typename


【解决方案1】:

鉴于您的代码确实有效,我不完全确定我是否理解您的问题。但在风格上,对于产生类型的元函数,该类型应命名为type。所以你应该有:

using type = decltype( test((T*)0) );
      ^^^^

或者,为了避免零指针强制转换:

using type = decltype(test(std::declval<T*>()));

另外,您的test 不需要定义。只是声明。我们实际上并没有调用它,只是检查它的返回类型。也不必是constexpr,这样就足够了:

template<class U>
static std::true_type test(Base<U> *);
static std::false_type test(...);

一旦你有了它,你就可以给它起别名:

template <typename T>
using is_Base_t = typename is_Base<T>::type;

并使用别名:

template <typename T, 
          typename = std::enable_if_t< is_Base_t<T>::value>>
void foo(T const&)
{
}

【讨论】:

  • 我定义了函数来消除叮当声警告。该别名与我的 passoff hack 非常相似。没有办法在 enable_if 中直接说 is_Base&lt;T&gt;::type::value 吗?
  • @Cory 是的。准确输入。
  • 我收到一个错误。我试过在各个地方添加typename,但我想我只是不知道propper格式。
  • 哦,好的。完全没有typename。哈哈。谢谢。
  • 啊,我不知道他们在c ++ 14中添加了_t类型别名'。别名解决方案当然更干净。我现在接受这个答案。
【解决方案2】:

在 cmets 中盲目地找到答案后,我发现我可以使用 is_Base&lt;T&gt;::type::value 而不使用任何 typename 关键字。之前尝试删除static_passoff 时,我一直在输入typename。我一直和那个混在一起。无论如何,这是巴里回答中的一些柚木的最终代码:

#include <iostream>
#include <memory>

using namespace std;

template < typename D >
class Base
{
public:
    typedef D EType;
};

template<class T>
struct is_Base
{
    using base_type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

    template<class U>
    static constexpr std::true_type test(Base<U> *) { return std::true_type(); }
    static constexpr std::false_type test(...) { return std::false_type(); }

    using type = decltype(test(std::declval<T*>()));
};

template <typename T, typename = typename std::enable_if< is_Base< T >::type::value >::type >
void foo(T const&)
{
}


class Derived : public Base<Derived> {};
class NotDerived {};


int main()
{
    Derived d;
    //NotDerived nd;

    foo(d);
    //foo(nd); // <-- Should cause compile error

    return 0;
}

【讨论】:

  • 次要,假设 Barry 不会让我发表评论,您可以将 using base_type 减少到 using base_type = std::decay_t&lt;T&gt; 或 C++11 using base_type = typename std::decay&lt;T&gt;::type; (en.cppreference.com/w/cpp/types/decay)
  • @kfsone 我收回它。看起来decay 在这里很有用。
猜你喜欢
  • 2022-01-20
  • 1970-01-01
  • 2013-11-24
  • 2018-08-26
  • 2014-01-29
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 2013-10-13
相关资源
最近更新 更多