【问题标题】:Is it possible to write a C++ template to check for a constructor's existence?是否可以编写 C++ 模板来检查构造函数的存在?
【发布时间】:2014-10-03 03:09:50
【问题描述】:

这个问题在精神上是另一个用户的这个问题的后续,它有一些很好的答案: Is it possible to write a template to check for a function's existence?

我想完全按照这个问题中的描述做,除了我希望能够为构造函数做这件事。例如,给定这两种类型:

class NormalType
{
public:
    NormalType()
    {
        std::cout << "NormalType::NormalType()" << std::endl;
    }
};

class SpecialType
{
public:
    SpecialType()
    {
        std::cout << "SpecialType::SpecialType()" << std::endl;
    }
    SpecialType(int someArg)
    {
        std::cout << "SpecialType::SpecialType(int someArg)" << std::endl;
    }
};

还有这个构造对象的辅助函数:

template<class T>
class ConstructHelper
{
public:
    template<bool HasSpecialConstructor>
    static T Construct()
    {
        return T();
    }
    template<>
    static T Construct<true>()
    {
        return T(int(42));
    }
};

我希望能够编写这样的代码:

NormalType normalType = ConstructHelper<NormalType>::Construct<has_special_constructor<NormalType>::value>();
SpecialType specialType = ConstructHelper<SpecialType>::Construct<has_special_constructor<SpecialType>::value>();

期望的结果是调用NormalType::NormalType(),并调用SpecialType::SpecialType(int someArg)。这里缺少的部分是关键的has_special_constructor 帮助器,它可以确定我们的特殊构造函数是否存在于给定类型。

我引用的上一个问题涉及检查一个给定的函数是否存在于一个类型上,并且提出了各种可行的解决方案。不幸的是,它们中的大多数依赖于能够获取目标方法的地址,并且根据 C++ 规范,您不能获取构造函数 (12.1.10) 的地址。在剩余的工作解决方案中,它们似乎都依赖于带有 decltype 的 SFINAE 和模板专业化中的任意表达式。这是解决此问题的一种简单方法,但不幸的是,我正在开发 Visual Studio 2013,它不能正确支持 C++11 SFINAE 规则,并且在“Visual Studio 14”的发布中仍然不支持.有了适当的 SFINAE 支持,我应该能够做到这一点,例如:

template<class T>
struct has_special_constructor
{
    template<class S>
    struct calculate_value: std::false_type {};
    template<>
    struct calculate_value<decltype(T(int(42)))>: std::true_type {};

    static const bool value = calculate_value<T>::value;
};

但是如果我尝试测试一个没有定义我的目标构造函数的类型,由于缺乏 SFINAE 支持,它不会在 VS2013 下编译。也就是说,我还不相信这是不可能的,我认为可能有办法让它发挥作用,但到目前为止我还没有找到解决方案。有没有人看到我忽略的方法?

这里有一些关于我需要什么的更多信息才能接受答案作为这个问题的解决方案:

  • 必须能够为任何给定类型解析has_special_constructor&lt;T&gt;::value,而无需为该特定类型编写额外代码。

  • 我主要针对 Visual Studio 2013,因此任何解决方案都必须在该环境中工作。我知道完全符合 C++11 的编译器可以更轻松地解决这个问题,但我正在寻找可以在我当前的目标编译器上运行的东西。

  • 如果有人可以提供在 C++03 编译器(IE,没有任何 C++11 功能)中工作的解决方案,我会接受使用 C++11 功能的解决方案。

  • 此时我会接受基于 MSVC 扩展的解决方法,因为我可以使用预处理器回退到此方法,直到全面支持 C++11。

【问题讨论】:

    标签: c++ templates visual-studio-2013 sfinae decltype


    【解决方案1】:
    template<class T>
    using has_special_constructor = std::is_constructible<T, int>;
    

    可能的“C++03”版本:

    template <class T>
    struct has_special_constructor {
      typedef char one;
      typedef struct { char _[2];} two;
    
      template <std::size_t>
      struct dummy {};
    
      template<class U>
      static one f(dummy<sizeof(U(42))>*);
      template<class>
      static two f(...);
    
      static const bool value = sizeof(f<T>(0)) == sizeof(one);
    };
    

    这适用于 g++ 4.4 或更高版本的 C++03 模式。我把“C++03”放在了可怕的引号中,因为这取决于表达式 SFINAE,seems to be a bit of a gray area in C++03 - 显然 C++03 的措辞似乎允许它,但直到 C++11 几乎没有主要编译器供应商真正支持它这里(GCC 4.4 于 2009 年发布),所以“纯”C++03 是否允许它是有争议的......

    【讨论】:

    • 哈!就那么简单!我需要再次浏览 C++11 类型特征列表并将它们提交到我认为的内存中。我只花了 3 个小时寻找解决这个问题的方法。
    • 对于奖励积分*(好吧,不是真的,但如果可以的话我会的!)如果可以在 C++03 编译器中模拟 std::is_constructible 有什么想法吗?
    • @RogerSanders 查看我的编辑。我相信您需要为此表达 SFINAE,我猜它是一种 C++03。
    • 感谢 C++03 示例,尽管在 Visual Studio 中没有运气,即使在 2013 年也是如此。我尝试修改它,但我得到了编译器错误或错误的结果我尝试过的一切。我现在很确定如果没有更好的 SFINAE 支持,没有 C++11 类型特征就无法做到这一点。不过,C++03 支持对于我的问题并不是必不可少的。谢谢,你帮了大忙。
    • @RogerSanders 甚至 Visual Studio 2013 doesn't support 表达式 SFINAE
    猜你喜欢
    • 2013-01-10
    • 2011-02-11
    • 1970-01-01
    • 2015-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    相关资源
    最近更新 更多