最近我偶然发现了VS 2017中的Visual C++编译器一致性模式切换.我读到了这个解释 ,其中给出了以下关于交换机如何禁止编译不符合代码的说明
template<typename T>
struct B {
int f();
};
template<typename T>
struct D : B<T> {
int g();
};
template<typename T>
int D<T>::g() {
return f(); // error: should be ‘this->f()’
}
Run Code Online (Sandbox Code Playgroud)
在D :: g的定义中,符号f来自依赖基类B,但标准C++ 在查找满足f的使用的声明时不允许检查依赖基类.这是Visual C++长期以来无法诊断的源代码中的错误.
好的,很好,我明白了.除了一件事.为什么?
为什么标准不容许检查对于f依赖基类()?这项禁令的理由是什么?标准是否给出了一个?
如果B和D都只是常规的非模板结构,则f()将被正确地解释为对基类(er ... base struct)成员函数的调用.那么为什么当它们是模板时却没有这样做呢?
(我确信这是一个很好的理由但是目前我的理解有限,这似乎是一种烦恼.我确实尝试搜索这个并找到至少一个关于它的问题,但没有关于它的"为什么")
c++ templates standards-compliance visual-c++ visual-studio-2017
以及如何修复代码?
这是代码: https: //godbolt.org/z/vcP6WKvG5
#include <memory>
#include <utility>
enum class Format {
Number,
Text,
};
template <template <Format> typename Visitor, typename... Args>
void switchByFormat(Format format, Args&&... args) {
switch(format) {
case Format::Number:
Visitor<Format::Number>::visit(std::forward<Args>(args)...);
break;
case Format::Text:
Visitor<Format::Text>::visit(std::forward<Args>(args)...);
break;
}
}
struct AstNode {};
template <Format format>
struct ANode: public AstNode {};
using AstNodePtr = std::shared_ptr<AstNode>;
template <template <Format> typename AstNodeT,
typename... Args>
struct AstNodeFactory {
template <Format format>
struct Visitor {
static void visit(AstNodePtr& result, Args&&... args)
{
result = …Run Code Online (Sandbox Code Playgroud) 有人可以告诉我为什么以下代码在Visual Studio 2010中完美运行但无法在gcc 5.3中编译,尽管它似乎没有任何问题吗?我已经做了一些谷歌搜索但没有运气找到一个清晰和标准的方式来描述模板类继承.
#include <iostream>
#include <string>
namespace foobar
{
template <typename Char_Type = char>
class basic_foo
{
public:
inline basic_foo(){}
virtual ~basic_foo(){}
typedef std::basic_string< Char_Type > str_foo;
enum { fooEnum = 100 };
};
template <typename Char_Type = char>
class basic_bar :private basic_foo <Char_Type>
{
public:
basic_bar(){}
~basic_bar(){}
str_foo bar1()
{
int i = fooEnum;
return str_foo("test succeeded\n");
}
};
}
typedef foobar::basic_bar<> bar2;
int main()
{
bar2 bar;
std::cout << bar.bar1();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在visual studio中,它会导致:
test …Run Code Online (Sandbox Code Playgroud) template<class T>
void foo()
{
M
}
Run Code Online (Sandbox Code Playgroud)
除非我实例化它,否则Visual C++不会告诉我上面的代码包含错误.为什么是这样?
我正在研究两个阶段名称查找.一个非常合乎逻辑的解释表明,其中一个主要原因是遵循C++哲学尽早捕获错误.
我的问题是为什么这种哲学不遵循非模板化方法.而不是检查何时以及是否调用该方法,为什么不在实例化模板化类时检查阶段2中的所有非模板化方法?
例如:
template <class T>
struct X {
auto foo() // non-templated (important)
{
T t{};
return t.non_existing();
}
};
int main()
{
X<int> x; // (1) this compiles OK.
// somewhere is a galaxy far far away,
// maybe deep inside some unrelated code
x.foo(); // (2) the error is here
}
Run Code Online (Sandbox Code Playgroud)
如果你从不写(2)程序编译并运行没有任何问题,虽然foo对于实例化是非法的X<int>.
无论你是否打过电话,我认为第(1)行应该产生错误foo.
在编写模板化类时,这可以让错过一个错误直到你最终调用有问题的方法(2),而不是在实例化模板化类(1)时得到错误.
另外,健全性检查:如果我实例化X<int>(1)但从不调用X<int>::foo(2),代码是否有效?或者它是否像"形成不良,无需诊断"?如果是后者,那么这是更早发现错误的原因.
假设我有一个模板函数:
template <class T>
void tfoo( T t )
{
foo( t );
}
Run Code Online (Sandbox Code Playgroud)
后来我想用一个类型,所以我声明/定义一个函数并尝试调用它:
void foo( int );
int main()
{
tfoo(1);
}
Run Code Online (Sandbox Code Playgroud)
我从g ++得到错误:
'foo'未在此范围内声明,并且在实例化时没有通过参数依赖查找找到声明[-fpermissive] foo(t);
为什么它void foo(int)在实例化时找不到?它在那时宣布.有没有办法让它工作(没有移动foo模板之前的声明)?