VS2012 SP1(+十一包)未知类型错误(类似C :: a(T& ...)) [英] VS2012 SP1 (+november pack) unknown-type errors (alike C::a(T &&...) )

查看:184
本文介绍了VS2012 SP1(+十一包)未知类型错误(类似C :: a(T& ...))的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此, ms编译器无法编译此(作为我的家VS2012与SP1(+十一月pack)),而 ang和现代gcc可以。可以aany一个请高高我在VS中缺少C ++ 11功能,并有办法吗?

  #include< iostream> 
#include< utility>
#include< type_traits>

struct A {
int x;

void a(){
std :: cout< an a!<< x<< \\\
;
}
};

struct B {
double x;

double b(double k){
std :: cout< b!<< x<< ,< k<< \\\
;
return x - k;
}

void b(){
std :: cout< b!<< x<< ,?\\\
;
}
};

struct C {
A * _first__;
B * _second__;
C(A * _first__,B * _second __):_ first __(_ first__),_second __(_ second__){
}类型名称K,类型名称... T> static auto _a_caller __(K * k,T& ... args) - > decltype(k-> a(std :: forward T(args)...)){
return k-> a(std :: forward T(args)...);
}
template< typename ... T> auto a(T& ... args) - > decltype(_a_caller __(_ first__,std :: forward< T>(args)...)){
return _a_caller __(_ first__,std :: forward< T>(args)...);
}
template< typename ... T> auto a(T& ... args) - > decltype(_a_caller __(_ second__,std :: forward< T>(args)...)){
return _a_caller __(_ second__,std :: forward< T>(args)...);
}
template<类型名称K,类型名称... T> static auto _b_caller __(K * k,T& ... args) - > decltype(k-> b(std :: forward< T>(args)...)){
return k-> b(std :: forward T(args)...);
}
template< typename ... T> auto b(T& ... args) - > decltype(_b_caller __(_ first__,std :: forward< T>(args)...)){
return _b_caller __(_ first__,std :: forward< T>(args)...);
}
template< typename ... T> auto b(T& ... args) - > decltype(_b_caller __(_ second__,std :: forward< T>(args)...)){
return _b_caller __(_ second__,std :: forward< T>(args)...);
}
};

int main(){
A a {12};
B b {24};

C c(& a,& b);

c.a();
c.b();
std :: cout<< c.b(2445)<< std :: endl;
}

错误:

  testvc.cpp 
- \ testvc.cpp(38):error C2535:'unknown-type C :: a(T& ...) :成员函数已定义或声明
- \ testvc.cpp(33):参见声明'C :: a'
- \ testvc.cpp(47):error C2535:未知类型C :: b(T& ...)':已定义或声明的成员函数
--\ testvc.cpp(42):参见'C :: b'
- \testvc.cpp(56):错误C2893:无法专门化函数模板'unknown-type C :: a(T& ...)'
使用以下模板参数:
''
- \ testvc.cpp(57):错误C2893:无法专门化函数模板'unknown-type C :: b(T& ...)'
使用以下模板参数:
''
--\testvc.cpp(58):错误C2893:无法专门化函数模板'未知类型C :: b(T& & ...)'
使用以下模板参数:
'int'


解决方案

[此回答已更新。请参阅文字结尾处的 EDIT ]



我将此归为 SSCCE

  #include< iostream> 

struct A {A g(int){return A(); }};
struct B {B g(){return B(); }};

struct C
{
template< typename ... Ts>
auto f(Ts ... ts) - > decltype(A().g(ts ...))
{std :: cout< f - > A<< std :: endl; return A(); }

template< typename ... Ts>
auto f(Ts ... ts) - > decltype(B()。g(ts ...))
{std :: cout< f - > B<< std :: endl; return B(); }
};

int main()
{
C c;
c.f(1);
}

GCC 4.7.2和Clang 3.2编译,而VC11没有。实际上,当在 decltype 表达式中取代失败时,VC11不适用SFINAE,这很可能是错误



事实上,C ++ 11标准规定了(14.8.2 / 7):


替换出现在函数类型和模板参数声明中使用的所有类型和表达式中。表达式不仅包括常量表达式,例如出现在数组边界或非类型模板变量中的常量表达式,还包括内的一般表达式(即非常量表达式)sizeof decltype 和允许非常量表达式的其他上下文。 [...]


与SFINAE相关的还有14.8.2 / 8,其中:


如果替换导致无效的类型或表达式,类型扣除失败。无效的类型或表达式是如果使用替换参数写入将是不成形的。 [...]只有在函数类型及其模板参数类型的立即上下文 中的无效类型和表达式可能导致扣除失败。


这是一个替代失败的情况在直接上下文吗?同一段落澄清了直接上下文的含义:


注:实例化,生成隐式定义的函数等。这种副作用


在我简单的例子中,替换失败肯定发生在直接上下文中,因为它不涉及模板实例化或特殊化。因此,VC11肯定包含错误



但是,不太明显是否在在立即上下文中,因为在 decltype 表达式中,尝试了一个函数模板( _b_caller __



这里的关键观察是尝试实例化,但永远不会执行,因为类型扣除失败(再次,由于尝试实例化的模板函数的 decltype 子句中的表达式的替换失败)。因此,错误不会发生在模板实例化的嵌套上下文中。



因此,这可以作为 VC11错误 >

PS:请参阅此Q&

编辑: p>

原来我的答案是不正确,但我决定保留原文,因为我相信推理是不重要的,可能有助于一些。但是,我忽略了一个重要方面。



由于 Johannes Schaub 在下面的注释中正确指出,上面的 f()的第二个定义是错误的,不需要诊断。这由C ++ 11标准的第14.6 / 8段规定:


[...]如果每个有效的可变参数模板需要一个空的模板参数包,模板定义是错误的,无需诊断。 [...]


因此,尽管程序不正常,但编译器不是必需的发出错误。这意味着编译此程序失败是VC11的不是错误,而是一个很好的特性,编译器检测到一个错误,它不需要检测(虽然必须说错误消息是相当误导)。


So ms compiler online could not compile this (as wall as my home VS2012 with SP1 (+november pack)) while clang and modern gcc could. Can aany one please tall me what C++11 feature is missing in VS and is there ways around?

#include <iostream>
#include <utility>
#include <type_traits>

struct A {
    int x;

    void a() {
        std::cout << "an a! " << x << "\n";
    }
};

struct B {
    double x;

    double b(double k) {
        std::cout << "b! " << x << ", " << k << "\n";
        return x - k;
    }

    void b() {
        std::cout << "b! " << x << ", ?\n";
    }
};

struct C {
    A *_first__;
    B *_second__;
     C(A * _first__, B * _second__):_first__(_first__), _second__(_second__) {
    } template < typename K, typename ... T > static auto _a_caller__(K * k, T && ... args)->decltype(k->a(std::forward < T > (args) ...)) {
    return k->a(std::forward < T > (args)...);
    }
    template < typename...T > auto a(T &&...args)->decltype(_a_caller__(_first__, std::forward < T > (args)...)) {
        return _a_caller__(_first__, std::forward < T > (args)...);
    }
    template < typename...T > auto a(T &&...args)->decltype(_a_caller__(_second__, std::forward < T > (args)...)) {
        return _a_caller__(_second__, std::forward < T > (args)...);
    }
    template < typename K, typename...T > static auto _b_caller__(K * k, T && ... args)->decltype(k->b(std::forward < T > (args) ...)) {
        return k->b(std::forward < T > (args)...);
    }
    template < typename...T > auto b(T &&...args)->decltype(_b_caller__(_first__, std::forward < T > (args)...)) {
        return _b_caller__(_first__, std::forward < T > (args)...);
    }
    template < typename...T > auto b(T &&...args)->decltype(_b_caller__(_second__, std::forward < T > (args)...)) {
        return _b_caller__(_second__, std::forward < T > (args)...);
    }
};

int main() {
    A a {12};
    B b {24};

    C c (&a, &b);

    c.a();
    c.b();
    std::cout << c.b(2445) << std::endl;
}

Errors:

testvc.cpp
--\testvc.cpp(38) : error C2535: 'unknown-type C::a(T &&...)' : member function already defined or declared
        --\testvc.cpp(33) : see declaration of 'C::a'
--\testvc.cpp(47) : error C2535: 'unknown-type C::b(T &&...)' : member function already defined or declared
        --\testvc.cpp(42) : see declaration of 'C::b'
--\testvc.cpp(56) : error C2893: Failed to specialize function template 'unknown-type C::a(T &&...)'
        With the following template arguments:
        ''
--\testvc.cpp(57) : error C2893: Failed to specialize function template 'unknown-type C::b(T &&...)'
        With the following template arguments:
        ''
--\testvc.cpp(58) : error C2893: Failed to specialize function template 'unknown-type C::b(T &&...)'
        With the following template arguments:
        'int'

解决方案

[This answer has been updated. See the EDIT at the end of the text]

I brought this down to an SSCCE:

#include <iostream>

struct A { A g(int) { return A(); } };
struct B { B g() { return B(); } };

struct C
{
    template<typename... Ts>
    auto f(Ts... ts) -> decltype(A().g(ts...)) 
    { std::cout << "f -> A" << std::endl; return A(); }

    template<typename... Ts>
    auto f(Ts... ts) -> decltype(B().g(ts...)) 
    { std::cout << "f -> B" << std::endl; return B(); }
};

int main()
{
    C c;
    c.f(1);
}

GCC 4.7.2 and Clang 3.2 compile this, while VC11 does not. Indeed it seems VC11 does not apply SFINAE when substitution fails inside the decltype expression, and this is most likely a bug.

In fact, the C++11 Standard specifies (14.8.2/7):

The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. [...]

Also relevant to SFINAE is 14.8.2/8, which adds:

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [...] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

So is this a case of substitution failure "in an immediate context"? The same paragraph clarifies what is meant by "immediate context":

Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the "immediate context" and can result in the program being ill-formed.

In the case of my simplified example, the substitution failure definitely occurs in an immediate context, as it involves no template instantiation or specialization whatsovever. Thus, VC11 definitely contains a bug.

However, it is less obvious whether in your example the substitution happens in an "immediate context", because inside the decltype expression a function template (_b_caller__) instantiation is attempted.

The key observation here is that the instantiation is attempted but never performed, because type deduction fails (again, due to substitution failure for the expression in the decltype clause of the template function whose instantiation is attempted). Thus, the error does not occur in the nested context of a template instantiation.

Hence, this qualifies as a VC11 bug.

P.S.: See this Q&A on SO for a situation where SFINAE does not apply because substitution failure occurs in a nested context.

EDIT:

It turns out my answer was incorrect, but I decided to keep its original text because I believe the reasoning is non-trivial and might be helpful to some. However, I overlooked one important aspect.

As Johannes Schaub correctly pointed out in a comment below, the second definition of f() above is ill-formed and no diagnostic is required. This is dictated by Paragraph 14.6/8 of the C++11 Standard:

[...] If every valid specialization of a variadic template requires an empty template parameter pack, the template definition is ill-formed, no diagnostic required. [...]

Thus, although the program is ill-formed, compilers are not required (even though they are allowed) to issue an error. This means that failure to compile this program is NOT a bug of VC11, but rather a good feature, in that the compiler detects an error it is not required to detect (although it must be said that the error message is quite misleading).

这篇关于VS2012 SP1(+十一包)未知类型错误(类似C :: a(T&amp; ...))的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆