我被以下代码严重咬了,我浪费了很多宝贵的时间.
#include<string>
int next(std::string param){
return 0;
}
void foo(){
next(std::string{ "abc" });
}
Run Code Online (Sandbox Code Playgroud)
这会产生以下编译器错误(在Visual Studio 2013上):
1>------ Build started: Project: sandbox, Configuration: Debug Win32 ------
1> test.cpp
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility(371): error C2039: 'iterator_category' : is not a member of 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>'
1> c:\users\ray\dropbox\programming\c++\sandbox\test.cpp(8) : see reference to class template instantiation 'std::iterator_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>' being compiled
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility(371): error C2146: syntax error : missing ';' before identifier 'iterator_category'
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility(371): error C4430: …Run Code Online (Sandbox Code Playgroud) 考虑以下MCVE
struct A {};
template<class T>
void test(T, T) {
}
template<class T>
class Wrapper {
using type = typename T::type;
};
template<class T>
void test(Wrapper<T>, Wrapper<T>) {
}
int main() {
A a, b;
test(a, b); // works
test<A>(a, b); // doesn't work
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里test(a, b);有效,但test<A>(a, b);失败:
<source>:11:30: error: no type named 'type' in 'A'
using type = typename T::type;
~~~~~~~~~~~~^~~~
<source>:23:13: note: in instantiation of template class 'Wrap<A>' requested here
test<A>(a, b); …Run Code Online (Sandbox Code Playgroud) 关于以下代码(https://wandbox.org/permlink/nhx4pheijpTF1ohf为方便起见,下面转载)
#include <type_traits>
#include <utility>
namespace foo_name {
template <typename T>
void foo();
template <>
void foo<int>();
template <typename T>
struct c_size;
template <>
struct c_size<int> : public std::integral_constant<int, 1> {};
} // namespace foo_name
template <typename Type>
class Foo {
public:
template <typename T>
static decltype(auto) impl(T&& t) {
using foo_name::foo;
return foo(std::forward<T>(t));
}
};
class Something {};
template <typename Type, typename T = std::decay_t<Type>>
using EnableIfHasFoo = std::void_t<
decltype(Foo<T>::impl(std::declval<T>())),
decltype(foo_name::c_size<Type>::value)>;
template <typename Type, typename = std::void_t<>> …Run Code Online (Sandbox Code Playgroud) 考虑一下:
template <typename T>
struct hash
{
static_assert(false,"Not implemented.");
};
struct unhashable {};
template <typename T>
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int);
void test(...);
int main()
{
std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value;
}
Run Code Online (Sandbox Code Playgroud)
除了显然缺少标题,这应该编译吗?
换句话说,我问的是,如果在推断重载函数模板的返回值的同时触发尾随decltype内部的静态断言失败是否要求停止编译,或者是否只是丢弃了重载.
在gcc 4.7上,编译失败.我很积极,虽然这将在gcc 4.8中编译好(但在此刻无法检查).谁是对的?
我已经阅读了一些关于SFINAE的文章,但找不到我的案例的解决方案.这就是我想要做的事情:
#include <type_traits>
struct CByteArray {};
struct HLVariant {
HLVariant() {}
HLVariant(const HLVariant&) {}
HLVariant(const CByteArray&) {}
};
template <typename T>
struct Serializer
{
static inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
static_assert(std::is_pod<T>::value, "Not a POD type");
return CByteArray();
}
static inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
return Serializer<HLVariant>::serialize(HLVariant(value));
}
};
template <>
struct Serializer<HLVariant>
{
static inline CByteArray serialize(const HLVariant& value)
{
return CByteArray();
}
};
int main()
{
int i = 0;
Serializer<int>::serialize(i);
Serializer<CByteArray>::serialize(CByteArray());
Serializer<HLVariant>::serialize(HLVariant()); …Run Code Online (Sandbox Code Playgroud) friend在评估std::is_constructible和评估时,Clang和GCC似乎不尊重声明std::is_destructible.
关于`is_constructible,cppreference.com说:
从与T无关的上下文和Args中的任何类型执行访问检查.仅考虑变量定义的直接上下文的有效性.
(该网站没有解释如何is_destructible处理访问检查,但访问修饰符确实会影响is_destructible一般的行为,所以我希望它的工作方式与之相同is_constructible.)
因此,在我看来,这个代码应该不编译,因为在直接背景检查构造函数和析构函数都是可用的,由当地变量实例为证:
class Private
{
Private() {}
~Private() {}
friend class Friend;
};
class Friend
{
public:
Friend()
{
// Both of these should fire, but they do not.
static_assert(
!std::is_constructible<Private>::value,
"the constructor is public");
static_assert(
!std::is_destructible<Private>::value,
"the destructor is public");
// There is no error here.
Private p;
}
};
Run Code Online (Sandbox Code Playgroud)
...但Coliru编译它没有错误(使用GCC或Clang).
这是两个编译器中的错误(或至少是不合格),或者cppreference.com是否歪曲了标准,还是我误解了cppreference.com的声明?
假设我们有一个当前类:
template<typename T>
struct Inheriter : public T {};
Run Code Online (Sandbox Code Playgroud)
T请注意,仅当/未声明为时class,其实例化才是格式正确的。structfinal
然后,借助 SFINAE 的强大功能,std::void_t我们可以在编译时检查类型是格式良好还是格式错误。让我们用它来编写我们自己的简单实现std::is_final:
template<typename T, typename = void>
struct IsFinal : public std::true_type{};
template<typename T>
struct IsFinal<T, std::void_t<decltype(Inheriter<T>{})>> : public std::false_type{};
Run Code Online (Sandbox Code Playgroud)
对于任何任意类型,T编译器都应该实例化最专业的版本IsFinal,如果替换失败,则尝试实例化最不专业的版本。并且只有当所有这些都失败时,编译器才必须吐出错误。
但是在 Clang 14 和 GCC 11.2(目前最新的)上,当我们将某种final类型作为模板参数传递给时IsFinal,我们会收到编译错误(https://godbolt.org/z/q8jxP3Thc)。
为什么编译器不尝试实例化最不专业的版本IsFinal,并直接吐出错误?这是编译器错误还是 C++ 语言标准的某些棘手部分?
c++ metaprogramming sfinae language-lawyer template-meta-programming
这段代码无法在大多数编译器中编译,但起初我直观地期望SFINAE保护我:
typedef void (*A)();
template < typename T >
struct a_metafun { typedef typename T::type type; };
template < typename T >
typename a_metafun<T>::type f(T) {}
template < typename T>
void f(T(*)()) {}
int main() { f(A()); }
Run Code Online (Sandbox Code Playgroud)
我可以通过至少两种方式解决问题:
1)将"metafun"f()的定义更改为:
template < typename T >
typename T::type f(T) {}
2)定义"a_metafun",使得它分析T并且如果T有一个则有一个类型,如果没有则不具有...但是在没有错误的情况下实例化:
BOOST_MPL_HAS_XXX_TRAIT_DEF(type)
typedef < template T, bool = has_type<T>::value >
struct a_metafun { };
typedef < template T >
struct a_metafun<T, true> { typedef typename T::type type };
Run Code Online (Sandbox Code Playgroud)
在查看14.8.2(C++ 03)时,我认为它确切地说明了SFINAE可以应用的条件.有没有更好的地方看?在已经推断出的模板的实例化中失败,即使在扣除另一个模板时,也不会包含在此列表中.
我用来解释造成这种非法行为的另一个方向是,a_metafun的演绎已经发生,其内部的实例化是导致错误的原因.SFINAE在实例化期间不适用,但仅在扣除期间适用,或者我错在那里?但是在第二种情况下,a_metafun正确,并且格式良好地实例化,但它内部没有"类型"定义,这意味着试图实例化它的模板由于替换而失败. …
template <bool Cond, typename Type = void>
using Enable_if = typename std::enable_if<Cond, Type>::type;
class Degree;
template <typename T>
constexpr inline bool Is_Degree() {
return std::is_base_of<Degree, T>::value;
}
class Degree {
public:
std::size_t inDeg = 0;
};
template <typename Satellite = Degree>
class Vertex: public Satellite {
public:
explicit Vertex(int num): n(num) {}
private:
std::size_t n;
};
template <typename Satellite = Degree>
class Edge {
public:
// i want have different constructor depending on
// whether Vertex is (directly or indirectly) …Run Code Online (Sandbox Code Playgroud) 这些类之间有什么区别?这些方法与enable_if完全一样。
/// Alias of std::enable_if...
template <bool B, typename T = void>
using Enable_if = typename std::enable_if<B, T>::type;
Template<typename T, std::size_t N>
class A {
...
template <std::size_t NN = N,
typename = Enable_if<NN == 2>>
Some_Return_Type
method(param1, param2)
{}
template <std::size_t NN = N,
typename = Enable_if<NN == 1>>
Some_Return_Type
method(param1)
{}
};
Template<typename T, std::size_t N>
class B {
...
Enable_if<N == 2, Some_Return_Type>
method(param1, param2)
{}
Enable_if<N == 1, Some_Return_Type>
method(param1)
{}
};
Run Code Online (Sandbox Code Playgroud)
在以下情况下,使用enable_if的正确方法是什么: