C++ 条件标记显式构造函数

C++ 条件标记显式构造函数,c++,c++17,C++,C++17,更新:已写入C++20草稿 有一堆C++17注释,内容如下: 此构造函数是显式的,当且仅当至少有一个i 如何编写条件显式的构造函数?首先想到的可能性是显式(true),但这不是合法的语法 如果未成功,则尝试使用启用\u: // constructor is explicit if T is not integral struct S { template <typename T, typename = typename std::enable_if<std

更新:已写入C++20草稿

有一堆C++17注释,内容如下:

此构造函数是显式的,当且仅当至少有一个
i

如何编写条件显式的构造函数?首先想到的可能性是显式(true),但这不是合法的语法

如果未成功,则尝试使用
启用\u:

// constructor is explicit if T is not integral
struct S {
  template <typename T,
            typename = typename std::enable_if<std::is_integral<T>::value>::type>
  S(T) {}

  template <typename T,
            typename = typename std::enable_if<!std::is_integral<T>::value>::type>
  explicit S(T) {}
};
//如果T不是整数,则构造函数是显式的
结构{
模板
S(T){}
模板::类型>
显式S(T){}
};
错误如下:

error: ‘template<class T, class> S::S(T)’ cannot be overloaded
explicit S(T t) {}
错误:“模板S::S(T)”不能重载
显式S(T){}

添加了一个示例说明其工作原理的提案:

考虑下面打算使用的类模板A 作为其他类型T的包装器:

#include <type_traits>
#include <utility>

template<class T>
struct A {
  template<class U,
    typename std::enable_if<
      std::is_constructible<T, U>::value &&
      std::is_convertible<U, T>::value
    , bool>::type = false
  >
  A(U&& u) : t(std::forward<U>(u)) {}

 template<class U,
    typename std::enable_if<
      std::is_constructible<T, U>::value &&
      !std::is_convertible<U, T>::value
    , bool>::type = false
  >
  explicit A(U&& u) : t(std::forward<U>(u)) {}

  T t;
};
#包括
#包括
模板
结构A{
template::type=false
>
A(U&&U):t(std::forward(U)){}
template::type=false
>
显式A(U&&U):t(std::forward(U)){
T;
};
显示的构造函数都使用完美转发,并且 基本上相同的签名,除了一个是显式的 另一个不是。此外,它们是相互排斥的。 换句话说:此组合适用于任何目标类型T 任何参数类型U都像一个构造函数 显式或非显式(或根本没有构造函数)

正如裁判官所指出的,这正是为什么

如果我们相应地修改OPs示例,它也会起作用:

struct S {
  template <typename T,
            typename std::enable_if< std::is_integral<T>::value, bool>::type = false>
  S(T) {}

  template <typename T,
            typename std::enable_if<!std::is_integral<T>::value, bool>::type = false>
  explicit S(T) {}
};
结构{
模板::type=false>
S(T){}
模板::type=false>
显式S(T){}
};

一种似乎适用于大多数编译器的方法是向其中一个函数添加一个伪参数,使它们略有不同

// constructor is explicit if T is integral

struct S {
  template <typename T,
            typename = typename std::enable_if<std::is_integral<T>::value>::type>
  S(T t) {}

  template <typename T,
            typename = typename std::enable_if<!std::is_integral<T>::value>::type,
            typename dummy = void>
  explicit S(T t) {}
};

int main()
{
   S  s1(7);

   S  s2("Hello");    
}
//如果T是整数,则构造函数是显式的
结构{
模板
S(T){}
模板::类型,
typename dummy=void>
显式S(T){}
};
int main()
{
s1(7);
S s2(“你好”);
}

使用MSVC 2015编译。

标准草案中有一些示例。在您的示例中,两个构造函数是相同的,因为默认参数不在签名中。也许有点像我的上帝只是。。极坏的对我来说没有C++17,这已经解决了。请看libstdc++,这正是Shafik发布的内容@LightnessRacesinOrbit在我看来,这是一个很好的解决方案,因为它允许您编写
返回{x,y,z}
在返回元组的函数中,假设所有涉及的类型都是隐式可转换的。@David:成功地说服那些想考虑X的人,在解决Y之前他们不应该考虑X,这通常意味着X和Y都不会发生请注意,在严格阅读本标准的情况下,对于某些类型的
T
,上述代码可能定义不清。
std
中的此类代码不是问题,因为
std
的实现是一个黑箱(它们可以自由执行UB或有一个技术上格式错误的程序,只要编译器对所述UB/格式错误做出正确的响应)。问题是,模板类的模板方法必须为每一组有效的模板类参数至少有一个有效的实例化吗?上次我检查时,标准不清楚。@Yakk我暂时无法进行任何真正的编辑,但我相信你是正确的。我有墨迹,但我让想法溜走了。@Yakk我似乎找不到一个完全适用于这种情况的引用,如果我读得正确,我认为需求是一个有效的实例化,不一定适用于每一组参数。您是否有任何缺陷报告等?“如果无法为模板生成有效的专门化,并且该模板未实例化,则该模板格式不正确,不需要诊断。”[temp.res]/8在n4527中。作为对原因的猜测,这似乎是“编译器可以自由检测对任何类型都无效的模板代码”的总括(这也打开了向标准中添加更多有效性检查的可能性)。问题是,这是否适用于模板类实例的模板方法?@Yakk我看到了这一点,但不清楚它是否适用于这种情况,我今天将进一步深入探讨。
typename std::enable_if*=0
在不使用
的情况下工作。