调用类型标记的构造函数(如果可用),否则默认为

时间:2017-10-06 20:36:33

标签: c++ c++11 constructor void template-meta-programming

我试图建立一些想要声明局部变量的代码(比如类型test,如下所示)。构造该局部变量应该使用一个构造函数,如果存在这样的构造函数,则采用特殊的Tag参数,否则使用默认的构造函数。

我们能够提出的内容如下,我们专门构建void参数或Tag参数,但编译器并不喜欢这样:

#include <iostream>
using std::cout;

struct Tag { };

template <bool z>
struct helper {
  using type = void;
};
template <>
struct helper<true> {
  using type = Tag;
};

template <bool z>
static typename helper<z>::type get_arg() {
  return typename helper<z>::type();
}

struct test {
  test(void) { cout << "test(void)\n"; }
  test(Tag x) { cout << "test(Tag)\n"; }

  test(const test&) = delete;
  test(test&&) = delete;
};

template <typename T>
void try_construct() {
  // we would be selecting from one of these by template metaprogramming
  T a{typename helper<false>::type()};
  T b{typename helper<true>::type()};

  T c{get_arg<false>()};
  T d{get_arg<true>()};

  // Then do stuff with the suitably-constructed instance of T
  // . . .
}

int main(void) {
  try_construct<test>();

  return 0;
}

编译器输出:

$ g++ -std=c++11 -c foo.cpp 
foo.cpp: In instantiation of 'void try_construct() [with T = test]':
foo.cpp:38:23:   required from here
foo.cpp:30:37: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
   T a{typename helper<false>::type()};
                                     ^
foo.cpp:30:37: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
   test(Tag x) { cout << "test(Tag)\n"; }
   ^
foo.cpp:22:3: note:   no known conversion for argument 1 from 'void' to 'Tag'
foo.cpp:21:3: note: test::test()
   test(void) { cout << "test(void)\n"; }
   ^
foo.cpp:21:3: note:   candidate expects 0 arguments, 1 provided
foo.cpp:33:23: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
   T c{get_arg<false>()};
                       ^
foo.cpp:33:23: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
   test(Tag x) { cout << "test(Tag)\n"; }
   ^
foo.cpp:22:3: note:   no known conversion for argument 1 from 'helper<false>::type {aka void}' to 'Tag'
foo.cpp:21:3: note: test::test()
   test(void) { cout << "test(void)\n"; }
   ^
foo.cpp:21:3: note:   candidate expects 0 arguments, 1 provided

我们知道如何测试构造函数的存在,所以我离开了我们的例子。如果这最终与采用不同方法的解决方案相关,请随意走这条路。

我们的最终目标是要求一个默认构造函数或Tag构造函数,以及复制或移动构造函数。

2 个答案:

答案 0 :(得分:3)

namespace details {
  template<class T>
  T maybe_tag_construct(std::true_type) {
    return T(Tag{});
  }
  template<class T>
  T maybe_tag_construct(std::false_type) {
    return T();
  }
}
template<class T>
T maybe_tag_construct() {
  return details::maybe_tag_construct<T>( std::is_constructible<T, Tag>{} );
}

现在auto t =maybe_tag_construct<test>();test构建Tag iff它是否有效。

之前移除构造也是如此,在中没有移动构造。

为了传递void左右的实例,您需要提出“常规无效”提案,该提案在我最后检查的上正在进行中。

答案 1 :(得分:1)

我认为沿着这些方向发挥作用:

#include <type_traits>

template <typename T, bool B = std::is_constructible<Tag, T>> struct H;
template <typename T>
struct H<T, false> {
  T t;
  H() : t() {}
};
template <typename T>
struct H<T, true> {
  T t;
  H() : t(Tag) {}
};

try_construct() {
  H<T> h;
  h.t;
}