boost::enable_if_c<> 条件参数是否使用短路?
Does the boost::enable_if_c<> conditional argument use short circuiting?
看到我代码底部的 is >> i
了吗?我希望 g++(C++03;我有理由)使用第一个 operator>>()
模板——打印 "non-container type" 的模板,因为右边的表达式是 int
而不是,例如,vector
。相反,它考虑最后一个 - 打印 "fixed-length container type." 的那个我可以从错误消息中看到它正在评估最后一个模板的 enable_if_c<>
条件参数,这会导致各种问题,因为 has_resize<T>::value
做一些不能在容器上工作的东西。
我本以为,由于 enable_if_c
的条件参数 is_container<C>::value
中的第一个子表达式的计算结果可能为 false,因此第二个子表达式 has_resize<C>::value
不会被计算.要么分隔两者的 &&
运算符没有短路,要么第一个子表达式对于 int
莫名其妙地计算为真。知道它是哪一个以及我能做些什么吗? (调试 TMP 真的很困难。我想逐步编译,因为编译器会考虑每个模板。)
哦,如果您将 #if 1
更改为 #if 0
,则会使用另一个 has_resize<T>
模板,这会按预期工作。但是,该模板不能很好地确定类型是否可调整大小,而这正是我正在尝试做的。我正在努力工作的那个也不是完美的工作,但它更好。
如果您想尝试一下代码,也可以在 Wandbox. (C++ shell, too. I'm playing around with online compilers. I made a list of them 上找到它。)
#include <iostream>
#include <boost/spirit/home/support/container.hpp>
#if 1
// has_resize<T>::value is whether the (presumably) container class contains resize.
template<class T>
class has_resize
{
struct Fallback { int resize; };
struct Derived : T, Fallback { };
template<class C, C>
class check;
typedef uint8_t no;
typedef uint16_t yes;
template<typename C> static no test(check<int Fallback::*, &C::resize> *);
template<typename C> static yes test(...);
public:
static const bool value = sizeof test<Derived>(0) == sizeof(yes);
};
#else
// has_resize<T>::value is whether the (presumably) container class contains allocator_type.
template <class T>
class has_resize
{
typedef uint8_t yes;
typedef uint16_t no;
template <typename C> static yes test(class C::allocator_type *);
template <typename C> static no test(...);
public:
static const bool value = sizeof test<T>(0) == sizeof(yes);
};
#endif
class xstream { }; // For this example, the class doesn't need to do anything.
template <typename T>
typename boost::enable_if_c<
!boost::spirit::traits::is_container<T>::value,
xstream &>::type
operator>>(xstream &ibs, T &b)
{
std::cout << "non-container type" << std::endl;
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "variable-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && !has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "fixed-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
int main()
{
int i;
xstream is;
is >> i;
}
更新:这是@Jarod42 建议的修复代码:
#include <iostream>
#include <vector>
#include <set>
#if __cplusplus > 199711L
#include <array>
#endif
#include <boost/spirit/home/support/container.hpp>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static char check(helper<signature, &funcName>*); \
template<typename T> static int check(...); \
public: \
static \
const bool value = sizeof(check<U>(0)) == sizeof(char); \
}
#if __cplusplus > 199711L
DEFINE_HAS_SIGNATURE(has_resize, T::resize, void (T::*)(typename T::size_type));
#else
DEFINE_HAS_SIGNATURE(has_resize, T::resize, void (T::*)(typename T::size_type, typename T::value_type));
#endif
class xstream { }; // For this example, the class doesn't need to do anything.
template <typename T>
typename boost::enable_if_c<
!boost::spirit::traits::is_container<T>::value,
xstream &>::type
operator>>(xstream &ibs, T &b)
{
std::cout << "non-container type" << std::endl;
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "variable-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && !has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "fixed-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
int main()
{
int i;
std::vector<int> vi;
std::set<int> si;
#if __cplusplus > 199711L
std::array<int, 1> ai;
#endif
xstream xs;
xs >> i >> vi >> si;
#if __cplusplus > 199711L
xs >> ai;
#endif
}
在你的情况下,你在 struct Derived : T, Fallback { };
中有一个硬错误
T = int
::value
强制实例化 class。
我使用以下:
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_resize, T::foo, int (T::*));
看到我代码底部的 is >> i
了吗?我希望 g++(C++03;我有理由)使用第一个 operator>>()
模板——打印 "non-container type" 的模板,因为右边的表达式是 int
而不是,例如,vector
。相反,它考虑最后一个 - 打印 "fixed-length container type." 的那个我可以从错误消息中看到它正在评估最后一个模板的 enable_if_c<>
条件参数,这会导致各种问题,因为 has_resize<T>::value
做一些不能在容器上工作的东西。
我本以为,由于 enable_if_c
的条件参数 is_container<C>::value
中的第一个子表达式的计算结果可能为 false,因此第二个子表达式 has_resize<C>::value
不会被计算.要么分隔两者的 &&
运算符没有短路,要么第一个子表达式对于 int
莫名其妙地计算为真。知道它是哪一个以及我能做些什么吗? (调试 TMP 真的很困难。我想逐步编译,因为编译器会考虑每个模板。)
哦,如果您将 #if 1
更改为 #if 0
,则会使用另一个 has_resize<T>
模板,这会按预期工作。但是,该模板不能很好地确定类型是否可调整大小,而这正是我正在尝试做的。我正在努力工作的那个也不是完美的工作,但它更好。
如果您想尝试一下代码,也可以在 Wandbox. (C++ shell, too. I'm playing around with online compilers. I made a list of them 上找到它。)
#include <iostream>
#include <boost/spirit/home/support/container.hpp>
#if 1
// has_resize<T>::value is whether the (presumably) container class contains resize.
template<class T>
class has_resize
{
struct Fallback { int resize; };
struct Derived : T, Fallback { };
template<class C, C>
class check;
typedef uint8_t no;
typedef uint16_t yes;
template<typename C> static no test(check<int Fallback::*, &C::resize> *);
template<typename C> static yes test(...);
public:
static const bool value = sizeof test<Derived>(0) == sizeof(yes);
};
#else
// has_resize<T>::value is whether the (presumably) container class contains allocator_type.
template <class T>
class has_resize
{
typedef uint8_t yes;
typedef uint16_t no;
template <typename C> static yes test(class C::allocator_type *);
template <typename C> static no test(...);
public:
static const bool value = sizeof test<T>(0) == sizeof(yes);
};
#endif
class xstream { }; // For this example, the class doesn't need to do anything.
template <typename T>
typename boost::enable_if_c<
!boost::spirit::traits::is_container<T>::value,
xstream &>::type
operator>>(xstream &ibs, T &b)
{
std::cout << "non-container type" << std::endl;
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "variable-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && !has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "fixed-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
int main()
{
int i;
xstream is;
is >> i;
}
更新:这是@Jarod42 建议的修复代码:
#include <iostream>
#include <vector>
#include <set>
#if __cplusplus > 199711L
#include <array>
#endif
#include <boost/spirit/home/support/container.hpp>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static char check(helper<signature, &funcName>*); \
template<typename T> static int check(...); \
public: \
static \
const bool value = sizeof(check<U>(0)) == sizeof(char); \
}
#if __cplusplus > 199711L
DEFINE_HAS_SIGNATURE(has_resize, T::resize, void (T::*)(typename T::size_type));
#else
DEFINE_HAS_SIGNATURE(has_resize, T::resize, void (T::*)(typename T::size_type, typename T::value_type));
#endif
class xstream { }; // For this example, the class doesn't need to do anything.
template <typename T>
typename boost::enable_if_c<
!boost::spirit::traits::is_container<T>::value,
xstream &>::type
operator>>(xstream &ibs, T &b)
{
std::cout << "non-container type" << std::endl;
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "variable-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
template <typename C>
typename boost::enable_if_c<
boost::spirit::traits::is_container<C>::value && !has_resize<C>::value,
xstream &
>::type
operator>>(xstream &ibs, C &c)
{
std::cout << "fixed-length container type" << std::endl;
ibs >> *c.begin();
return ibs;
}
int main()
{
int i;
std::vector<int> vi;
std::set<int> si;
#if __cplusplus > 199711L
std::array<int, 1> ai;
#endif
xstream xs;
xs >> i >> vi >> si;
#if __cplusplus > 199711L
xs >> ai;
#endif
}
在你的情况下,你在 struct Derived : T, Fallback { };
中有一个硬错误
T = int
::value
强制实例化 class。
我使用以下:
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_resize, T::foo, int (T::*));