C++ c++;可变模板构造函数和公共构造函数
类似(c++14)的代码:C++ c++;可变模板构造函数和公共构造函数,c++,templates,constructor,c++14,variadic-templates,C++,Templates,Constructor,C++14,Variadic Templates,类似(c++14)的代码: 在构造函数中没有附加标记的情况下,您可以启用可变构造函数,当且仅当这些参数不允许您使用其他方式构造C 即: template <typename... T, typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value> > C(T&&... ) { } 模板 > C(T&&…{}
在构造函数中没有附加标记的情况下,您可以启用可变构造函数,当且仅当这些参数不允许您使用其他方式构造
C
即:
template <typename... T,
typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value>
>
C(T&&... ) { }
模板
>
C(T&&…{}
有了这个变化,
cc1{s}
确实调用了(2)
和cc2{“abc”,3}
确实调用了(1)
,而cc7{1,2,3,4,5}
将调用(4)
创建两层构造函数。然后标记调度
template<template<class...>class Z, class T>
struct is_template:std::false_type{};
template<template<class...>class Z, class...Ts>
struct is_template<Z, Z<Ts...>>:std::true_type{};
struct foo {
private:
template<class T> struct tag{ explicit tag(int) {} };
public:
foo( tag<std::true_type>, const char*, size_t );
template<class...Ts>
foo( tag<std::false_type>, Ts&&...ts );
public:
foo() = default; // or whatever
template<class T0, class...Ts,
std::enable_if_t<!is_template<tag, std::decay_t<T0>>{},int> =0>
foo(T0&&t0, Ts&&...ts):
foo( tag<typename std::is_constructible< foo, tag<std::true_type>, T0&&, Ts&&... >::type>{0}, std::forward<T0>(t0), std::forward<Ts>(ts)... )
{}
};
就像我们在一个答案错误的上下文中实例化的那样,
是可构造的
。实际上,编译器会缓存模板实例化的结果,因此现在的结果是可构造的依赖于编译器顺序(我怀疑是ODR冲突)。这是另一个不使用标记分派的解决方案。在这里,构造函数是按选择的顺序进行测试的,可以使用带有可变模板的简单构造函数,而无需从接口可变模板构造函数完美转发。例如,我可以将构造函数与std::pair参数一起使用,并在其中使用括号初始值设定项列表{“String”,6}
,而不是显式传递std::pair(“String”,6)
,等等,如示例所示。该方法不仅可以控制构造函数的优先级,还可以控制其他成员重载的优先级。目前它需要一个助手类
我对不同的元编程技巧不熟悉,这只是一个建议。我不认为它需要改进
#include <type_traits>
#include <cstddef>
#include <iostream>
using namespace std;
您希望保持可变模板和非模板构造函数,并确保它首先调用非模板构造函数;这对吗?你呢?它没有被使用,这是故意的吗?问题是具有正向(通用)引用的构造函数“吃”任何东西,它们比所有其他构造函数都更受欢迎。@Lorenzo Belli U只是表明C是模板。解决问题可能是语义上的,但C
在您的任何示例中都不是一个模板。我有点困惑:为什么这不会导致无限递归模板实例化?@dyp我相信这个构造函数直到它的声明符结束时才会被考虑。请参阅最后的int
参数时,可变因子应产生更好的重载。当SFINAE被停用时,它被称为“确实”。所以在这个是可构造的检查中似乎考虑了后面的系数。@dypintx=0;C{x};标准::cout不应该是可构造的
接受
?这太棒了,顺便说一句。是可构造的
应该在不相关的上下文中执行访问检查(即,没有私有的CTOR)。@T.C.修复。通过要求调用私有模板,使它们成为伪私有的。@barry我认为是为了防止{}
构造标记。现在调用者必须标记{0}
,这不能在类之外完成,因为他们不能命名类型标记
@TobiasHermann,它应该被称为是\u模板的\u实例
。当且仅当第二个参数是第一个参数模板的实例时,才为真。在这里,我使用它来防止公共构造函数吃掉标记的构造函数调用。
template<template<class...>class Z, class T>
struct is_template:std::false_type{};
template<template<class...>class Z, class...Ts>
struct is_template<Z, Z<Ts...>>:std::true_type{};
struct foo {
private:
template<class T> struct tag{ explicit tag(int) {} };
public:
foo( tag<std::true_type>, const char*, size_t );
template<class...Ts>
foo( tag<std::false_type>, Ts&&...ts );
public:
foo() = default; // or whatever
template<class T0, class...Ts,
std::enable_if_t<!is_template<tag, std::decay_t<T0>>{},int> =0>
foo(T0&&t0, Ts&&...ts):
foo( tag<typename std::is_constructible< foo, tag<std::true_type>, T0&&, Ts&&... >::type>{0}, std::forward<T0>(t0), std::forward<Ts>(ts)... )
{}
};
template <typename... T,
typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value>
>
C(T&&... ) { }
#include <type_traits>
#include <cstddef>
#include <iostream>
using namespace std;
struct null_helper { static constexpr int const value = 0; };
template<template<unsigned> typename Helper, unsigned order, typename ...TT>
class constructible_from_order
{
using PrevType = typename conditional<(order < 1), null_helper,
constructible_from_order<Helper, order-1, TT&&...>>::type;
static constexpr int const prev = PrevType::value;
static constexpr bool const is_this_constructible = is_constructible<Helper<order>, TT&&...>::value;
public:
static constexpr int const value = prev ? prev : is_this_constructible ? order : 0;
}; // template class constructible_from_order
template<template<unsigned> typename Helper, unsigned order, typename ...TT>
using enable_in_order = enable_if<(constructible_from_order<Helper, order, TT&&...>::value == order)>;
template<template<unsigned> typename Helper, unsigned order, typename ...TT>
using enable_in_order_t = typename enable_in_order<Helper, order, TT&&...>::type;
using blob_data = pair<char const*, size_t>;
class C {
template<unsigned order>
class helper
{
public:
helper(char const*, size_t) {} // 1
helper(blob_data const&, blob_data const&) {} // 1
template<typename T, typename = enable_if_t<(order == 2) && sizeof(T)>>
helper(blob_data const&, T&&) {} // 2
template<typename T, typename = enable_if_t<(order == 3) && sizeof(T)>>
helper(T&&, blob_data const&) {} // 3
template <class... Ts, typename = enable_if_t<(order == 4) && sizeof...(Ts)>>
helper(Ts&&... ) {} // 4
}; // template class helper
public: // constructors:
// order 1
C(char const*, size_t) { cout << "1" << endl; }
// order 1
C(blob_data const&, blob_data const&) { cout << "1" << endl; }
// order 2
template<typename T, typename = enable_in_order_t<helper, 2, blob_data const&, T&&>>
C(blob_data const&, T&&) { cout << "2" << endl; }
// order 3
template<typename T, typename = enable_in_order_t<helper, 3, T&&, blob_data const&>>
C(T&&, blob_data const&) { cout << "3" << endl; }
// order 4
template <class... Ts, typename = enable_in_order_t<helper, 4, Ts&&... >>
C(Ts&&... ) { cout << "4" << endl;}
public: // member functions:
// order 1
void fun(char const*, size_t) { cout << "1" << endl; }
// order 1
void fun(blob_data const&, blob_data const&) { cout << "1" << endl; }
// order 2
template<typename T, typename = enable_in_order_t<helper, 2, blob_data const&, T&&>>
void fun(blob_data const&, T&&) { cout << "2" << endl; }
// order 3
template<typename T, typename = enable_in_order_t<helper, 3, T&&, blob_data const&>>
void fun(T&&, blob_data const&) { cout << "3" << endl; }
// order 4
template <class... Ts, typename = enable_in_order_t<helper, 4, Ts&&... >>
void fun(Ts&&... ) { cout << "4" << endl;}
}; // class C
int main() {
char const* str = "aaa";
// constructors:
cout << "Constructors: " << endl;
cout << "1: "; C c1 { str, size_t{5} };
cout << "1: "; C cx { { str, 5 }, { str, 5 } };
cout << "2: "; C c2 { { str, 5 }, str };
cout << "3: "; C c3 { str, { str, 5 } };
cout << "4: "; C c4 { str, str };
cout << endl;
// functions:
cout << "Functions: " << endl;
cout << "1: "; c1.fun( str, size_t{5} );
cout << "1: "; c1.fun( { str, 5 }, { str, 5 } );
cout << "2: "; c1.fun( { str, 5 }, str );
cout << "3: "; c1.fun( str, { str, 5 } );
cout << "4: "; c1.fun( str, str );
cout << endl;
} // main
Constructors:
1: 1
1: 1
2: 2
3: 3
4: 4
Functions:
1: 1
1: 1
2: 2
3: 3
4: 4