当前位置: 首页 > 知识库问答 >
问题:

vs2015u2与gcc的不同constexpr行为

唐啸
2023-03-14

我有一个<code>std::tuple</code>,其中填充了从类模板实例化的对象和一个类型参数。现在我想在编译时从元组中获取一个具有指定类型参数的元素。代码如下:

template<typename Params, typename Descriptor>
struct IsParamsEqual;

template<typename Params1, typename Params2, ApiCommand::Value value>
struct IsParamsEqual<Params1, Descriptor<value, Params2>>
{
    static constexpr bool v = std::is_same<Params1, Params2>::value;
};

template<typename Params, size_t I, typename... Args>
constexpr size_t getIndexByParamsHelper(const IndexSequence<I>&, const std::tuple<Args...> &)
{
    return I;
}

template<typename Params, size_t I, size_t... Indexes, typename... Args>
constexpr size_t getIndexByParamsHelper(const IndexSequence<I, Indexes...> &, 
                                        const std::tuple<Args...> &tuple)
{
    return IsParamsEqual<Params, typename std::tuple_element<I, std::tuple<Args...>>::type>::v ?
           I : getIndexByParamsHelper<Params>(IndexSequence<Indexes...>(), tuple);
}

template<typename Params, size_t... Indexes, typename... Args>
constexpr size_t getIndexByParams(const IndexSequence<Indexes...> &seq, 
                                  const std::tuple<Args...> &tuple)
{
    return getIndexByParamsHelper<Params>(seq, tuple);
}

template<typename Params, typename... Args>
constexpr auto getByParamsImpl(const std::tuple<Args...> &tuple)
{
    constexpr size_t I = getIndexByParams<Params>(
        typename MakeIndexSequence<sizeof...(Args)>::type(), tuple);
    static_assert(std::is_same<typename std::remove_reference<decltype(
         std::get<I>(tuple))>::type::paramType, Params>::value,
         "Param not found");
    return std::get<I>(tuple);
}

这在gcc 4.8.4上编译正常,但在vs2015u2上不行。错误在getByParamsImpl()中,它说:

错误 C2131:表达式未计算为常量
注意:失败是由非常量参数或对非常量符号的引用引起的,
请参阅“I”的用法

显然,编译器认为getIndexByParams()返回值不是constexpr。

为什么,更重要的是,如何解决这个问题?

共有2个答案

养俊驰
2023-03-14

由于我不能随便扔掉“坏”编译器,所以我实施了解决方法。也许它会帮助某人。

template<typename Params, typename Descriptor>
struct IsParamsEqual;

template<typename Params1, typename Params2, ApiCommand::Value value>
struct IsParamsEqual<Params1, Descriptor<value, Params2>>
{
    static constexpr bool v = std::is_same<Params1, Params2>::value;
};

template<typename Params, typename IS, typename... Args>
struct GetIndexByParam;

template<typename Param, typename... Args>
struct GetIndexByParam<Param, IndexSequence<>, Args...>
{
    typedef typename std::integral_constant<size_t, 0> type;
};

template <typename Param, size_t I, size_t... IndexesTail,  typename Head, 
    typename ...Tail>
struct GetIndexByParam<Param, IndexSequence<I, IndexesTail...>, Head, Tail...>
{
    typedef typename std::conditional<IsParamsEqual<Param, Head>::v,
        std::integral_constant<size_t, I>,
        typename GetIndexByParam<Param, IndexSequence<IndexesTail...>, Tail...>::type >::type type;
};

template<typename Params, typename... Args>
constexpr auto getByParamsImpl(const std::tuple<Args...> &tuple)
{
    typedef typename GetIndexByParam<Params,        
        typename MakeIndexSequence<sizeof...(Args)>::type, Args...>::type IndexValueType;
    static_assert(std::is_same<
        typename std::remove_reference<decltype(std::get<IndexValueType::value>(tuple))>::type::paramType, \
            Params>::value, "Parameter not found");
    return std::get<IndexValueType::value>(tuple);
}
牟飞沉
2023-03-14

如果我做对了,你想做什么

constexpr std::tuple<int, float, int> t1{ 8, 2.0f, 1 };
constexpr std::tuple<int, float, double> t2{ 1, 2.0f, 3.0 };
constexpr std::tuple<unsigned, float, double> t3{ 1u, 2.0f, 3.0 };

constexpr auto f1 = find_by_type<int>(t1);
constexpr auto f2 = find_by_type<double>(t2);
constexpr auto f3 = find_by_type<unsigned>(t3);

哪里

  • f1应该等价于的配置文件int f1=8;
  • f2应该等价于constexr双f2=3.0;
  • f3应该等价于constexr无符号f3=1u;

您可以通过参数包递归得到类似的结果:

// helper
template<class ... Ts> struct Finder;
// empty to have compiler error if type is not found
template<class T> struct Finder<T> {  };

// if first type in pack is type to find, we stop
template<class ToFind, class ... Ts>
struct Finder<ToFind, ToFind, Ts...>
{
  constexpr static std::size_t N = 0u;
};

// if first type in pack is not type to find
// we increase by one and go down the pack
template<class ToFind, class First, class ... Amongst>
struct Finder<ToFind, First, Amongst...>
{
  constexpr static std::size_t N = 1u + Finder<ToFind, Amongst...>::N;
};

template<class P, class ... Args>
constexpr auto find_by_type(const std::tuple<Args...> &t)
{
  return std::get<Finder<P, Args...>::N>(t);
}
 类似资料:
  • 让我们举一个简单的例子: 取决于代码是什么,clang会抱怨或否。如果代码是: clang抱怨: 错误:Constexpr函数永远不会产生常量表达式[-Wvalid-Constexpr] 注意:非constexpr函数'运算符 /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../..//include/c/4.8/ostream:530:5:注意:此处声明

  • 我试图使用clang和gcc交叉编译一个项目,但在使用时,我发现了一些奇怪的差异,例如。 现在,当涉及NAN时,我期望类型行为,但clang和gcc给出不同的结果: 当我使用它时,_mm_max_ps做了预期的事情。我尝试过使用,,但似乎没有效果。有什么想法可以让编译器之间的行为相似吗? 这里是锁销连接

  • 运行这个简单的程序时,根据编译器的不同,观察到不同的行为。 它在由GCC 11.2编译时打印,在由MSVC 19.29.30137编译时打印(两者都是截至今天的最新版本)。 相关引文(摘自最新的C 23工作草案N4901): 给定 20.15.5.4 [元一元道具], (如11.4.5.3/11[class . copy . ctor],11.4.6/9 [class.copy.assign],1

  • 结果:1 2 3 有人能解释为什么会发生这种情况,以及我如何让非并行版本给出与并行版本相同的结果吗?

  • C++1z将引入“constexpr if”-一个将根据条件删除其中一个分支的if。似乎合理有用。 但是,没有constexpr关键字就不行吗?我认为在编译过程中,编译器应该知道编译时是否知道条件。如果是的话,即使是最基本的优化级别也应该移除不必要的分支。 例如(参见godbolt:https://godbolt.org/g/ipy5y5): Godbolt explorer显示,即使带有-o0的

  • 什么时候只能使用其中的一个? 何时可以同时使用和如何选择一个?