小编bog*_*dan的帖子

函数模板的部分排序 - 模糊调用

考虑一下这段C++ 11代码:

#include <iostream>
#include <cstddef>

template<typename T> void f(T, const char*) //#1
{ 
    std::cout << "f(T, const char*)\n"; 
}

template<std::size_t N> void f(int, const char(&)[N]) //#2
{ 
    std::cout << "f(int, const char (&)[N])\n"; 
}

int main()
{
    f(7, "ab");
}
Run Code Online (Sandbox Code Playgroud)

好吧,那么...选择哪个超载?在使用编译器输出溢出bean之前,让我们试着解释一下.

(所有对部分的引用都是针对C++ 11,ISO/IEC 14882:2011的最终标准文档.)

T#1推断出int,N#2推断出来3,两个专业都是候选者,两者都是可行的,到目前为止都很好.哪一个最好?

首先,考虑将函数参数与函数参数匹配所需的隐式转换.对于第一个参数,在任何一种情况下(身份转换)都不需要转换,int无处不在,所以这两个函数同样好.对于第二个,参数类型是const char[3],并且两个转换是:

  • 对于#1,数组到指针的转换,类别左值转换,根据[13.3.3.1.1]; 在根据转换序列进行比较时会忽略此转换类别[13.3.3.2],因此这与此目的的身份转换 …

c++ templates ambiguous c++11

46
推荐指数
1
解决办法
1231
查看次数

在列表初始化中缩小转换为bool - 奇怪的行为

考虑一下这段C++ 11代码:

#include <iostream>

struct X
{
    X(bool arg) { std::cout << arg << '\n'; }
};

int main() 
{
    double d = 7.0;
    X x{d};
}
Run Code Online (Sandbox Code Playgroud)

在初始化过程中,从double到bool的转换范围正在缩小x.根据我对标准的理解,这是错误的代码,我们应该看到一些诊断.

Visual C++ 2013发出错误:

error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion
Run Code Online (Sandbox Code Playgroud)

但是,Clang 3.5.0和GCC 4.9.1都使用以下选项

-Wall -Wextra -std=c++11 -pedantic 
Run Code Online (Sandbox Code Playgroud)

编译此代码没有错误,也没有警告.运行程序输出1(不出意外).


现在,让我们深入到陌生的领域.

改变X(bool arg)X(int arg)和,突然间,我们从锵得到一个错误

error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会发出警告

warning: …
Run Code Online (Sandbox Code Playgroud)

c++ standards-compliance narrowing c++11 list-initialization

24
推荐指数
1
解决办法
2245
查看次数

在哪个位置发生模板实例化绑定?

此代码来自Bjarne Stroustrup的"C++编程语言"(C.13.8.3实例化绑定点)

template <class T>
void f(T value)
{
    g(value);
}

void g(int v);

void h()
{
    extern g(double);
    f(2);
}
Run Code Online (Sandbox Code Playgroud)

他提到:

这里,f()的实例化点恰好在h()之前,因此在f()中调用的g()是全局g(int)而不是局部g(double)."实例化点"的定义意味着模板参数永远不能绑定到本地名称或类成员.

void h()
{
    struct X {}; // local structure
    std::vector<X> v; // error: can't use local structure as template parameter
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 为什么第一个代码有效?g()稍后声明,我真的得到了G ++ 4.9.2的错误,那时g没有声明.

  2. extern g(double) - 这是如何工作的?因为在函数重载的情况下返回值无关紧要,那么我们可以在前向声明中错过它吗?

  3. f()的实例化点就在h()之前 - 为什么?在f(2)被调用时它会被实例化是不合逻辑的?就在我们称之为的地方,它g(double)已经在范围内了.

  4. "实例化点"的定义意味着模板参数永远不能绑定到本地名称或类成员 - 在C++ 14中是否已更改?我在使用C++(G ++ 4.9.2)时遇到错误,但是在C++ 14(G ++ 4.9.2)中没有出错.

c++ templates name-binding c++14 template-instantiation

21
推荐指数
1
解决办法
589
查看次数

可变参数函数指针参数的模板参数推导 - 处理模糊情况

请考虑以下代码:

#include <iostream>

void f(int) { }

void f(int, short) { }

template<typename... Ts> void g(void (*)(Ts...))
{
   std::cout << sizeof...(Ts) << '\n';
}

template<typename T, typename... Ts> void h(void (*)(T, Ts...))
{
   std::cout << sizeof...(Ts) << '\n';
}

int main()
{
   g(f);         // #1
   g<int>(f);    // #2
   h(f);         // #3
   h<int>(f);    // #4
}
Run Code Online (Sandbox Code Playgroud)

目的是分别尝试身体中的每条线main().我的期望是所有四个调用都不明确并且会导致编译器错误.

我测试了代码:

  • Clang 3.6.0和GCC 4.9.2,两者都使用-Wall -Wextra -pedantic -std=c++14(-std=c++1y对于GCC) - 在所有这些情况下都是相同的行为,除了错误信息措辞的细微差别;
  • Visual C++ 2013 Update 4和Visual C++ 2015 CTP6 - …

c++ templates variadic-templates argument-deduction c++14

8
推荐指数
1
解决办法
500
查看次数

对于auto stdMaxInt = std :: max <int>,类型推断失败;

使用GCC 4.8.4 g++ --std=c++11 main.cpp输出以下错误

error: unable to deduce ‘auto’ from ‘max<int>’
auto stdMaxInt = std::max<int>;
Run Code Online (Sandbox Code Playgroud)

这个代码

#include <algorithm>

template<class T>
const T& myMax(const T& a, const T& b)
{
    return (a < b) ? b : a;
}

int main()
{
    auto myMaxInt = myMax<int>;
    myMaxInt(1, 2);

    auto stdMaxInt = std::max<int>;
    stdMaxInt(1, 2);
}
Run Code Online (Sandbox Code Playgroud)

为什么它适用myMax但不适用std::max?我们能让它与之合作std::max吗?

c++ function-templates auto type-deduction template-instantiation

6
推荐指数
1
解决办法
119
查看次数

可选择安全检查铸造可能不完整的类型

根据一个简单的,侵入式引用计数的对象系统,我有一个template<typename T> class Handle,它意味着用子类实例化CountedBase.Handle<T>拥有一个指向a的指针T,并且它的析构函数在该指针上调用DecRef(定义CountedBase).

通常,这会在尝试使用前向声明限制标头依赖性时导致问题:

#include "Handle.h"

class Foo; // forward declaration

struct MyStruct {
    Handle<Foo> foo; // This is okay, but...
};

void Bar() {
    MyStruct ms;
}   // ...there's an error here, as the implicit ~MyStruct calls
    // Handle<Foo>::~Handle(), which wants Foo to be a complete
    // type so it can call Foo::DecRef(). To solve this, I have
    // to #include the definition of Foo.
Run Code Online (Sandbox Code Playgroud)

作为解决方案,我重写 …

c++ incomplete-type template-instantiation

5
推荐指数
1
解决办法
100
查看次数

完全专业化的模板功能

我有一个在头文件中声明的函数模板.该函数是一个归档程序,它应该支持通过项目实现的其他几种类型(类).我们的想法是拥有一个基本模板声明,然后每个类专门针对它自己的类型.

// Archiver.h
template <class T> void archive(Archiver & archiver, const T & obj);
Run Code Online (Sandbox Code Playgroud)

此方法没有实现.现在我创建一个类(比方说Header),我希望它可以存档.因此,我打算专门研究这种方法.这就是我现在拥有的:

// Header.h
extern template void archive(Archiver & archiver, const Header & obj);
Run Code Online (Sandbox Code Playgroud)

我声明该函数是extern因为我在.cpp文件中实现它

// Header.cpp
template <> void archive(Archiver & archiver, const Header & obj)
{
 // Code here
}
Run Code Online (Sandbox Code Playgroud)

这给了specialization after instantiation.我也尝试过其他组合:

  1. 直接在头文件中实现,通常建议用于模板:我得到"多重定义"
  2. 在头文件中没有声明的.cpp文件中的实现:我undefined reference从另一个编译单元调用该方法时得到

那么实现这个是正确的呢?

编辑:

最初我决定使用模板,因为反向过程,unarchiving.基本上我可以写,unarchive<Header>()而不是unarchive_header()似乎更合适.

我相信我还应该提到我正在使用Android Studio和Gradle构建系统编译它,这就是为什么我使用gcc而不是g ++.我还给了gcc以下编译器标志:

-std=gnu++11 -fexceptions -fpermissive -lstdc++
Run Code Online (Sandbox Code Playgroud)

-fpermissive 是一种绝望的行为.

c++ gcc templates template-instantiation

1
推荐指数
1
解决办法
301
查看次数