【问题标题】:SFINAE on template instantiation error?SFINAE 关于模板实例化错误?
【发布时间】:2016-07-23 12:09:47
【问题描述】:

我要问的可能是不可能的,但我会问只是为了确定。正如之前在这个问题中提出和回答的:SFINAE and decltype(auto),具有自动返回类型的函数可能不是 SFINAE,因为返回类型的推导会导致模板实例化。在实例化期间,编译器会产生错误。

但是,也许有人知道一些疯狂的技巧,可以将一段代码中的实例化错误转化为另一段代码中的替换失败,从而引发 SFINAE?

以一段代码为例,它会导致错误:

#include <utility>

struct no_call_ops { };

struct caller
{
    // Goal is to detect whether a particular Handler type
    // will be ok to pass into caller
    template <typename Handler>
    auto operator() (Handler&& handler, int v)
    {
        handler(3.14);

        while (v--)
        {
            handler("hello world");
        }

        // etc...
        // more calls to handler that I don't want to
        // express in the trailing return type.
    }
};

struct fallback { };

struct tester
{
    // Would be nice if this fails substitution...
    template <typename Caller, typename Handler, typename... Args>
    auto operator() (Caller&& caller, Handler&& handler, Args&&... args)
        -> decltype(caller(handler, std::forward<Args>(args)...))
    { }

    fallback operator() (...) { return fallback{}; }  
};

// want detected_t to be "fallback"
using detected_t = decltype(tester{}(caller{}, no_call_ops{}, 42));

玩转the code on Godbolt here

谢谢!

【问题讨论】:

  • 您希望发生什么? no_call_ops 没有 operator(),所以试图调用它是一个错误。 SFINAE 仅适用于函数/类型的类型数据,而不适用于包含的代码。您可以将 sfinae 放在您的 operator() 上,以确保 Handler 是回调,但我不确定这是否是您想要的。 ...也许
  • 我想这就是我想要做的,是包含代码的 SFINAE。最终结果将是一切都编译,detected_tfallback 类型。因此,为什么我认为这可能是不可能的,因为我要求编译器丢弃它实例化的代码。为了进一步激发我想要做的事情,想象一下处理程序被多次调用,具有不同的类型。我不想在那里创建一个尾随返回类型,因为它对我来说太复杂了。
  • 不确定我到底做了什么...godbolt.org/g/v4Mn5i 但我确实使用了尾随返回类型。
  • 是的,这行得通(你甚至不需要int_t 的东西。我的要求是没有尾随返回类型,只有自动。我会稍微改变一下问题:P
  • 为什么没有尾随返回类型?因为您的真实代码比示例更复杂?或...此外,如果没有 int_t 的东西,它会根据 Handler 的返回类型(即,如果它不是整数类型)而中断。我认为

标签: c++ templates c++14 template-meta-programming sfinae


【解决方案1】:

这种尾随返回类型是否可接受?

#include <utility>
#include <functional>
using namespace std;

struct no_call_ops { };

template<class T>
using int_t = int;

struct caller
{
  template <typename Handler, int_t<typename result_of<Handler>::type> = 0>
  auto operator() (Handler&& handler, int) -> typename result_of<Handler>::type
  {
    handler(3.14);    
  }
};


struct fallback { };

struct tester
{
  template <typename Caller, typename Handler, typename... Args>
  auto operator() (Caller&& caller, Handler&& handler, Args&&... args) -> decltype(caller(handler, std::forward<Args>(args)...))
  { }

  fallback operator() (...) { return fallback{}; }  
};

using detected_t = decltype(tester{}(caller{}, no_call_ops{}, 42));

【讨论】:

  • 您可以尝试将处理程序填充到具有适当输入类型的 std::function 中,以简化必须执行大量 declval 的操作...或传入类型的参数包并执行declval()...
【解决方案2】:

这对你有用吗?

#include <utility>

struct no_call_ops { };

struct caller
{
  template <typename Handler, class = decltype( std::declval<Handler>()(3.14) )>
  decltype(auto) operator() (Handler&& handler, int)
  {
    handler(3.14);    
  }
};

struct fallback { };

struct tester
{
  template <typename Caller, typename Handler, typename... Args>
  auto operator() (Caller&& caller, Handler&& handler, Args&&... args) -> decltype(caller(handler, std::forward<Args>(args)...))
  { }

  fallback operator() (...) { return fallback{}; }  
};

using detected_t = decltype(tester{}(caller{}, no_call_ops{}, 42));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-17
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多