相关疑难解决方法(0)

类模板特化部分排序和函数合成

选择哪个类模板特化的首选规则包括将特化重写为函数模板,并通过函数模板[temp.class.order]的排序规则确定哪个函数模板更加专业化.考虑这个例子,然后:

#include <iostream>

template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;

template <class T, class U> struct A { };

template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> )     { return 2; }

int main() {
    std::cout << foo(A<int*, void>{});
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang都打印2在这里.这是有道理的一些前面的例子-推导对非推测的情况下(voidvoid_t<T>)只是忽略,所以推断<T, void_t<T>>反对<X*, void>成功,但推断<T*, void>针对<Y, void_t<Y>>在两个参数失败.精细. …

c++ templates partial-ordering language-lawyer

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

这种模板函数重载的情况使我无法理解

#include <iostream>

template<typename T>
struct identity
{
    typedef T type;
};

template<typename T> void bar(T) { std::cout << "a" << std::endl; }
template<typename T> void bar(typename identity<T>::type) { std::cout << "b" << std::endl; }

int main ()
{
    bar(5); // prints "a" because of template deduction rules
    bar<int>(5); // prints "b" because of ...?

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

我预计bar<int>(5)至少会产生歧义.这里涉及到关于模板函数重载决策的疯狂规则?

c++ templates language-lawyer overload-resolution

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

具有未受限上下文的函数模板的部分排序

在阅读另一个问题时,我遇到了部分排序问题,我将其缩减为以下测试用例

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

int main() {
  // GCC chokes on f(0, 0) (not being able to match against T1)
  void *p = 0;
  f(0, p);
}
Run Code Online (Sandbox Code Playgroud)

对于两个函数模板,进入重载分辨率的特化的函数类型是void(int, void*).但是,部分排序(根据comeau和GCC)现在说第二个模板更专业.但为什么?

让我通过部分排序,并显示我有问题的地方.可以Q被用于确定根据偏序的独特由上型14.5.5.2.

  • 变换参数列表T1(Q插入)(Q, typename Const<Q>::type*).参数的类型是AT=(Q, void*)
  • 转换参数列表T2 …

c++ templates partial-ordering function-templates template-argument-deduction

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

不是`void f(A <0>,tuple <T*...>)`比`f(a <I>,tuple <T*...>)更专业?

#include <tuple>

template<int I>
struct A {};

template<int I, typename... T>
void f(A<I>, std::tuple<T *...>) {}

template<typename... T>
void f(A<0>, std::tuple<T *...>) {}

int main()
{
    f(A<0>{}, std::tuple<char*, int*, float*>{});
}
Run Code Online (Sandbox Code Playgroud)

是不是f更专业的第二次超载?g ++ 4.9.2表示调用不明确,clang 3.6.0接受它.哪个编译器是对的?

有趣的是,如果你改变std::tuple<T *...>std::tuple<T...>,G ++是与它的罚款,我不明白.

c++ overloading compiler-errors function c++11

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

为什么函数参数类型上的enable_if会影响重载解析?

请参阅 godbolt 上的代码

#include <iostream>
#include <cmath>
#include <type_traits>

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

template <typename T>
void f(T, std::enable_if_t<std::is_floating_point_v<T>, T>) // 2
{
    std::cout << "Special\n";
}

/*template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> f(T, T) // 3
{
    std::cout << "Special\n";
}*/

int main()
{
    f(1.1, 1.1); // prints 'Primary'
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,std::enable_if应用于第二个函数模板重载的函数类型。该函数是通过 [T = double] 推导来调用的,并且它调用重载 1。但是,如果我注释掉重载 2 并将其替换为重载 3,那么编译器会抱怨该调用不明确。我也期望在第一种情况下,为什么编译器更喜欢重载 1 而不是 2?

我阅读了“函数模板重载”部分,但对我来说,重载 2 看起来更专业。

c++ language-lawyer enable-if function-templates-overloading

14
推荐指数
0
解决办法
77
查看次数

使用auto重载模板函数的分辨率

随着3次超载

template <class T> auto foo() { return 1; }
template <class T> int  foo() { return 2; }
template <class T> T    foo() { return 3; }
Run Code Online (Sandbox Code Playgroud)

以下是不良形成的?

static_cast<int(*)()>(&foo<int>)();
Run Code Online (Sandbox Code Playgroud)

Clang选择重载#2,而gcc无法编译(Demo)

当删除过载#1时,两者都同意选择过载#2(演示).

当删除重载#2时,gcc选择重载#1并且clang无法编译(Demo)

c++ templates overloading language-lawyer c++14

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

使用非推导上下文的部分特化排序

根据[temp.class.order]§14.5.5.2,t在此示例中选择部分特化:

template< typename >
struct s { typedef void v, w; };

template< typename, typename = void >
struct t {};

template< typename c >
struct t< c, typename c::v > {};

template< typename c >
struct t< s< c >, typename s< c >::w > {};

t< s< int > > q;
Run Code Online (Sandbox Code Playgroud)

等效f于此示例中的重载选择:

template< typename >
struct s { typedef void v, w; };

template< typename, typename = void >
struct t {};

template< typename …
Run Code Online (Sandbox Code Playgroud)

c++ templates partial-specialization partial-ordering language-lawyer

8
推荐指数
2
解决办法
525
查看次数

重载决策和显式模板参数

以下代码打印"func 2".

为什么编译器会在存在显式(未推断)模板参数的情况下将第二个模板视为更好的匹配?为什么没有歧义?

我很感激C++标准的引用.

#include <iostream>

template<class T>
struct identity
{
    typedef T type;
};

template<class T>
void func(T)
{
    std::cout << "func 1\n";
}

template<class T>
void func(typename identity<T>::type)
{
    std::cout << "func 2\n";
}

int main()
{
    func<int>(1);    
}
Run Code Online (Sandbox Code Playgroud)

c++ template-specialization overload-resolution

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

可变参数模板构造函数的扣除指南失败

我试图重现视频C++ Weekly - Ep 48 - C++ 17的Variadic的结果using,但失败了.问题可以简化为以下代码段.

假设我有这样的通用结构:

template <class... T>
struct Container {
    template <class... U>
    Container(U... us) {}
};
Run Code Online (Sandbox Code Playgroud)

现在我可以Container用任何参数初始化a ,比如

auto d = Container(1,2,3);
Run Code Online (Sandbox Code Playgroud)

但是,编译器永远不会知道它是什么类型d.要解决这个问题,我们应该提供一个扣除指南,例如

template <class... U>
Container(U...) -> Container<double, int, bool>
Run Code Online (Sandbox Code Playgroud)

根据视频,编译器现在应该知道d有类型Container<double, int, bool>.

但是,代码无法按预期工作.打印时typeid(d).name(),无论我如何更改演绎指南中的返回类型,输出将始终被9ContainerIJEE转换为Container<>,表明此指南根本不指导编译器.

我正在使用gcc-7-snapshot-20170402,视频中的编译器是gcc-7-snapshot-20170130.

谁能告诉我这里有什么问题?

更新:

顺便说一句,如果我明确写

Container<bool, int> d = Container(1,2,3);
Container<char, char, char> d = Container(1,2,3);
...
Run Code Online (Sandbox Code Playgroud)

代码将始终编译,并提供像9containerIJbiEE …

c++ gcc c++17

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

为什么匹配模板类上的部分类模板特化与另一个没有模板匹配的部分专业模棱两可?

这个问题可能很难在标题中的句子中描述,但这是一个最小的示例:

#include <iostream>
#include <type_traits>

template <class T, class U, class Enabler>
struct my_trait : std::false_type
{};

template <class T, class U>
struct my_trait<T, U, 
                std::enable_if_t<std::is_same<T, U>::value>> : std::true_type
{};

template <class T>
class temped
{};

template <class T>
struct my_trait<temped<T>, temped<T>, void> : std::false_type
{};

template <class T, class U>
using trait_t = my_trait<T, U, void>;

int main()
{
    std::cout << std::boolalpha;
    std::cout << trait_t<int, float>::value << std::endl;   // false
    std::cout << trait_t<int, int>::value << std::endl;     // true

    // …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae template-specialization

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

模板部分排序规则是否未指定?

我已经注意到很多关于模板的问题,这些问题是由于部分排序规则造成的,而且它们似乎彼此不一致.我以为我会自己深入了解标准并将其排除在外.忍受我.

gcc和clang似乎都同意用于确定模板排序的算法,但该算法实际上并未出现在标准中.没有特别的顺序:

推导值的一致性:

template <typename T> void foo(T, T); // (1)
template <typename T, typename U> void foo(T, U); // (2)
Run Code Online (Sandbox Code Playgroud)

temp.deduct.type/2清楚地表明Ps必须有一组推导出的值.但是在偏序规则中没有这样的陈述.所描述的算法仅进行成对P/A匹配,因此从(2)到(1)via的合成调用foo(U{}, V{})可以成功推导.gcc和clang都认为(1)更专业.

类型合成模板实例化

template <typename T>
struct identity { using type = T; };

template<typename T> void bar(T, T ); // (1) 
template<typename T> void bar(T, typename identity<T>::type ); // (2)
Run Code Online (Sandbox Code Playgroud)

这里,如果为(2)Unique2和()合成typename identity<Unique2>::type == Unique2,那么类型推导将在两个方向上成功并且调用bar(0,0)将是模糊的.然而,似乎是两种编译器,而不是简单地把typename identity<Unique2>::type作为Unique2_b,从而由式(2)(1)失败(基于隐含缺少一致性规则)制作模板扣除.

非推导的上下文遗漏

与前面的示例相同,但现在定义:

template <typename T> struct identity; template <> struct identity<int> …
Run Code Online (Sandbox Code Playgroud)

c++ templates language-lawyer

5
推荐指数
0
解决办法
44
查看次数

取决于std :: enable_if的不明确的部分专业化

我有以下代码:

#include <iostream>

template <class T, typename U = void> class A;

template <class T>
class C
{
public:
    typedef T Var_t;
};

template <class T>
class B : public C<T>
{
};

template <class T>
class A<B<T>>
{
public:
    A() { std::cout << "Here." << std::endl; }
};

template <class T>
class A<T, typename std::enable_if<
                             std::is_base_of<C<typename T::Var_t>, T>::value>
                             ::type>
{
public:
    A() { std::cout << "There." << std::endl;}
};

int main() 
{
    A<B<int>> a;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当编译器尝试使用参数实例化第二个部分专业化时B<int> …

c++ templates

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