标签: template-argument-deduction

带有强类型枚举的模板参数推导

如果我有一个普通(弱)枚举,我可以使用它的枚举值作为非类型模板参数,如下所示:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}
Run Code Online (Sandbox Code Playgroud)

并称之为: magic<Cat>(t)

据我所知,如果我有一个强类型的枚举,并且不想硬编码枚举类型,我最终得到:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}
Run Code Online (Sandbox Code Playgroud)

现在我得写:magic<Animal, Animal::Cat>(t)这似乎是多余的.

有没有办法避免输入枚举类和值,缺少

#define MAGIC(E, T) (magic<decltype(E), E>(T));
Run Code Online (Sandbox Code Playgroud)

c++ templates strong-typing template-argument-deduction c++17

23
推荐指数
2
解决办法
1万
查看次数

什么是C++ 17中的std :: vector deduction指南?

我阅读了有关std::vector使用cppreference的演绎指南.

例:

#include <vector>

int main() {
   std::vector<int> v = {1, 2, 3, 4};
   std::vector x{v.begin(), v.end()}; // uses explicit deduction guide
}
Run Code Online (Sandbox Code Playgroud)

所以,我有一些问题:

  • 什么是std::vectorC++ 17 中的演绎指南?

  • 为什么以及何时需要向量推导?

  • 在这里,是x一个std::vector<int>还是一个std::vector<std::vector<int>>

c++ templates vector template-argument-deduction c++17

23
推荐指数
3
解决办法
2341
查看次数

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

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

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
查看次数

模板自动返回类型和歧义

我有一个重载的模板函数:

template<typename T1, typename T2>
auto overMax(T1 a, T2 b)
{
    std::cout << __FUNCSIG__ << std::endl;

    return b < a ? a : b;
}

template<typename RT, typename T1, typename T2>
RT overMax(T1 a, T2 b)
{
    std::cout << __FUNCSIG__ << std::endl;

    return b < a ? a : b;
}
Run Code Online (Sandbox Code Playgroud)

如果我这样称呼它:

auto a = overMax(4, 7.2); // uses first template
auto b = overMax<double>(4, 7.2); // uses second template
Run Code Online (Sandbox Code Playgroud)

一切都很完美,但是

auto c = overMax<int>(4, 7.2); // error
Run Code Online (Sandbox Code Playgroud)

导致模棱两可的调用。

为什么 …

c++ templates template-argument-deduction c++17 visual-studio-2019

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

编译器如何使用转发引用推断出此类模板?

我正在研究自C++ 17以来可用的类模板推导.以下是我想问的代码:

#include <iostream>
#include <cmath>
using std::endl;
using std::cout;

template<typename T>
struct MyAbs {
     template<typename U>
     MyAbs(U&& u) : t(std::forward<T>(u))
     { cout << "template" << endl;}

#ifdef ON
    MyAbs(const T& t) : t(t) {}
#endif

    T operator()() const
    {
        return std::abs(t);
    }
    T t;
};

/*
  // may need the following
template<typename U>
MyAbs(U&&) -> MyAbs<typename std::remove_reference<U>::type>;
*/

int main()
{
    const double d = 3.14;
    cout << MyAbs(4.7)() << endl;
    cout << MyAbs(d)() << endl;    
    return 0;
} …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-argument-deduction c++17

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

为什么自动初始值设定项的自动和模板类型推导会有所不同?

我理解,给定一个支撑的初始化程序,auto将推导出一种类型std::initializer_list,而模板类型推导将失败:

auto var = { 1, 2, 3 };   // type deduced as std::initializer_list<int>

template<class T> void f(T parameter);

f({ 1, 2, 3 });          // doesn't compile; type deduction fails
Run Code Online (Sandbox Code Playgroud)

我甚至知道在C++ 11标准中指定的位置:14.8.2.5/5 bullet 5:

[如果程序有,则这是一个非推导的上下文]一个函数参数,其关联参数是初始化列表(8.5.4),但参数没有std :: initializer_list或者可能是cv-qualified std :: initializer_list的引用类型.[ 例如:

模板void g(T);

克({1,2,3}); //错误:没有推断T的参数

- 结束例子 ]

我不知道或不理解的是为什么存在这种类型演绎行为的差异.C++ 14 CD中的规范与C++ 11中的规范相同,因此标准化委员会可能不会将C++ 11行为视为缺陷.

有人知道为什么auto推导出支撑初始值设定项的类型,但是不允许使用模板吗?虽然对"这可能是原因"形式的推测性解释很有意思,但我对那些知道为什么标准是按原样编写的人的解释特别感兴趣.

c++ templates c++11 list-initialization template-argument-deduction

18
推荐指数
2
解决办法
1016
查看次数

为什么这个模板的调用不明确?

我声明了两个模板,第一个将参数x从type 转换T为type U,第二个从type转换U为type T.如果我cast用10 调用,编译器不会抱怨.我认为两者都符合要求使用,因此应该有歧义,这是真的吗?此代码打印10.

#include <iostream>

template<typename T, typename U>
U cast(T x) {
    return static_cast<U>(x);
}

template<typename T, typename U>
T cast(U x) {
    return static_cast<T>(x);
}

int main() {
    std::cout << cast<int,float>(10) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

c++ templates overload-resolution template-argument-deduction

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

用“ std :: function”和先前推导的模板参数替换失败-为什么?

考虑以下代码:

template <typename> 
struct S { };

void g(S<int> t);

template <typename T>
void f(T, std::function<void(S<T>)>);
Run Code Online (Sandbox Code Playgroud)

尝试调用时

f(0, g);
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

error: no matching function for call to 'f'
    f(0, g);
    ^

note: candidate template ignored: could not match 
      'function<void (S<type-parameter-0-0>)>' 
      against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
     ^
Run Code Online (Sandbox Code Playgroud)

Godbolt.org上的实时示例

While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context

In this case T can first be deduced by the passed argument …

c++ templates language-lawyer c++11 template-argument-deduction

18
推荐指数
2
解决办法
299
查看次数

为什么不能在`std :: reference_wrapper`s中推导出模板实例?

假设我有一些类型的对象T,我想把它放到一个引用包装器中:

int a = 5, b = 7;

std::reference_wrapper<int> p(a), q(b);   // or "auto p = std::ref(a)"
Run Code Online (Sandbox Code Playgroud)

现在我可以很容易地说if (p < q),因为引用包装器已转换为其包装类型.一切都很开心,我可以处理一组参考包装器,就像它们是原始对象一样.

(正如下面链接问题所示,这可以是生成现有集合的备用视图的有用方法,可以随意重新排列,而不会产生完整副本的成本,以及维护原始集合的更新完整性. )


但是,对于某些类,这不起作用:

std::string s1 = "hello", s2 = "world";

std::reference_wrapper<std::string> t1(s1), t2(s2);

return t1 < t2;  // ERROR
Run Code Online (Sandbox Code Playgroud)

我的解决方法是这个答案中定义一个谓词*; 但我的问题是:

为什么以及何时可以将运算符应用于引用包装器并透明地使用包装类型的运算符?为什么会失败std::string?它与std::string模板实例的事实有什么关系?

*)更新:根据答案,似乎使用std::less<T>()是一般解决方案.

c++ templates implicit-conversion reference-wrapper template-argument-deduction

17
推荐指数
2
解决办法
1061
查看次数

变量演绎指南不是由g ++采用的,由clang ++拍摄 - 谁是正确的?

请考虑以下代码:

template <typename... Types>
struct list
{
    template <typename... Args>
    list(Args...) 
    {
        static_assert(sizeof...(Types) > 0);
    }
};

template <typename... Args>
list(Args...) -> list<Args...>;

int main()
{
    list l{0, 0.1, 'a'};
}
Run Code Online (Sandbox Code Playgroud)

我希望decltype(l)如此list<int, double, char>.不幸的是,g ++ 7.2g ++ trunk失败了静态断言.clang ++ 5.0.0clang ++ trunk编译并按预期工作.

godbolt.org一致性观点

这是一个g ++错误吗?或者,为什么不应该遵循演绎指南


在构造函数上添加SFINAE约束似乎提供了所需的行为:

template <typename... Args, 
          typename = std::enable_if_t<sizeof...(Args) == sizeof...(Types)>>
list(Args...) 
{
    static_assert(sizeof...(Types) > 0);
}
Run Code Online (Sandbox Code Playgroud)

godbolt.org一致性观点

c++ templates variadic-templates template-argument-deduction c++17

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