SFINAE 关于 VS10 中的数组初始化
SFINAE on array initialization in VS10
关于cppreference/variant(4),转换构造函数描述如下:
Converting constructor. Constructs a variant holding the alternative type T_j
that would be selected by overload resolution for the expression F(std::forward<T>(t))
if there was an overload of imaginary function F(T_i)
for every T_i
from Types...
in scope at the same time, except that:
- An overload
F(T_i)
is only considered if the declaration T_i x[] = { std::forward<T>(t) };
is valid for some invented variable x
;
- If
T_i
is (possibly cv-qualified) bool
, F(T_i)
is only considered if std:remove_cvref_t<T>
is also bool
.
因为我与 Visual Studio 2010 相关,但仍然想要一个标准变体,所以我自己实现了一个。我遇到的问题以及我在这里寻求解决方案的问题是如何在 VS10 中实现第一个要点?如果表达式
,如何丢弃虚函数 F(T_i)
的重载
T_i x[] = { std::forward<T>(t) };
格式不正确?
在 VS15 中我可以写:
template<class T> using array_t = T[];
template<class UserType, class T_i, class = void>
struct Single_FUN_T_i {
using type = void(*)();
};
template<class UserType, class T_i>
struct Single_FUN_T_i<UserType, T_i,
decltype( array_t<T_i>{ std::declval<UserType>() }, void() )> {
// ^^ Here I check whether T_i[]{ declval<T>() } compiles
using type = T_i(*)(T_i);
};
但是在 VS10 中这不起作用,因为表达式 array_t<T_i>{ std::declval<UserType>() }
似乎不受支持(我知道别名模板也不起作用,但这不是问题)。
我认为这可能会让您更进一步。不使用数组初始化,而是使用 declval 实例化数组并尝试在其中插入元素。
// TestSfinae.cpp :此文件包含 'main' 函数。程序执行在那里开始和结束。
//
#include <iostream>
#include <utility>
#include <iostream>
#include <string>
#include <boost/utility/declval.hpp>
template<class A, class B, class = void>
struct X {
std::string msg;
X():msg("Fail"){};
};
template<class A, class B>
struct X<A, B, decltype(boost::declval<A[]>()[0]=boost::declval<B>(), void()) >
{
std::string msg;
X():msg("Pass"){};
};
int main(){
X<int,int> x;
std::cerr << x.msg << std::endl;;
X<int,std::string> y;
std::cerr << y.msg << std::endl;;
}
结果如预期
Pass
Fail
不幸的是,我认为我无法用 VS10 解决这个问题。这是因为 the aggregate initilization T object[]{args...}
仅适用于 C++11 而不是 VS10 的一部分。要在聚合初始化上执行 SFINAE,我不能写 decltype(T x[]= {arg})
但必须像我的示例那样写 decltype(array_t<T>{arg})
。
关于cppreference/variant(4),转换构造函数描述如下:
Converting constructor. Constructs a variant holding the alternative type
T_j
that would be selected by overload resolution for the expressionF(std::forward<T>(t))
if there was an overload of imaginary functionF(T_i)
for everyT_i
fromTypes...
in scope at the same time, except that:
- An overload
F(T_i)
is only considered if the declarationT_i x[] = { std::forward<T>(t) };
is valid for some invented variablex
;- If
T_i
is (possibly cv-qualified)bool
,F(T_i)
is only considered ifstd:remove_cvref_t<T>
is alsobool
.
因为我与 Visual Studio 2010 相关,但仍然想要一个标准变体,所以我自己实现了一个。我遇到的问题以及我在这里寻求解决方案的问题是如何在 VS10 中实现第一个要点?如果表达式
,如何丢弃虚函数F(T_i)
的重载
T_i x[] = { std::forward<T>(t) };
格式不正确?
在 VS15 中我可以写:
template<class T> using array_t = T[];
template<class UserType, class T_i, class = void>
struct Single_FUN_T_i {
using type = void(*)();
};
template<class UserType, class T_i>
struct Single_FUN_T_i<UserType, T_i,
decltype( array_t<T_i>{ std::declval<UserType>() }, void() )> {
// ^^ Here I check whether T_i[]{ declval<T>() } compiles
using type = T_i(*)(T_i);
};
但是在 VS10 中这不起作用,因为表达式 array_t<T_i>{ std::declval<UserType>() }
似乎不受支持(我知道别名模板也不起作用,但这不是问题)。
我认为这可能会让您更进一步。不使用数组初始化,而是使用 declval 实例化数组并尝试在其中插入元素。
// TestSfinae.cpp :此文件包含 'main' 函数。程序执行在那里开始和结束。 //
#include <iostream>
#include <utility>
#include <iostream>
#include <string>
#include <boost/utility/declval.hpp>
template<class A, class B, class = void>
struct X {
std::string msg;
X():msg("Fail"){};
};
template<class A, class B>
struct X<A, B, decltype(boost::declval<A[]>()[0]=boost::declval<B>(), void()) >
{
std::string msg;
X():msg("Pass"){};
};
int main(){
X<int,int> x;
std::cerr << x.msg << std::endl;;
X<int,std::string> y;
std::cerr << y.msg << std::endl;;
}
结果如预期
Pass
Fail
不幸的是,我认为我无法用 VS10 解决这个问题。这是因为 the aggregate initilization T object[]{args...}
仅适用于 C++11 而不是 VS10 的一部分。要在聚合初始化上执行 SFINAE,我不能写 decltype(T x[]= {arg})
但必须像我的示例那样写 decltype(array_t<T>{arg})
。