适用范围内的歧义

时间:2015-03-07 09:21:11

标签: c++ templates c++11 boost

使用 apply 函数时,我在以下代码中遇到歧义问题。它基于stackoverflow问题here

1)我有一个帮助器类,因为不允许模板化函数作为指针:

template<typename TT, class...Ts>
struct selector_helper
{
    static TT doSelect(Ts&&... params)
    {
        return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
    }
};

我尝试运行apply函数,但遇到了问题。我尝试了两个代码,但没有一个成功:

2.1)错误:apply:2个重载中没有一个可以转换所有参数类型

boost::tuple<Ts...> tpl;
return apply<T, Ts...>(selector_helper<T, Ts...>::doSelect, tpl);

2.2)这里我有两个错误:

  • 错误2错误C2782:&#39; Ret apply(Ret(__ cdecl *)(Args ...),boost :: tuples :: tuple&amp;&amp;)&#39; :模板参数&#39; Args&#39;是不明确的
  • 错误3错误C2782:&#39; Ret apply(Ret(__ cdecl *)(Args ...),const boost :: tuples :: tuple&amp;)&#39; :模板参数&#39; Args&#39;含糊不清

    boost::tuple<Ts...> tpl; 
    return apply(selector_helper<T, Ts...>::doSelect,   tpl);
    

修改:更多解释:

两个示例都在select方法中运行,该方法在类中:

class database
{
    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {
        // apply examples
    }
};

在这里打电话:

database db;
User result = db.select_<User, int, std::string, std::string>
    ("select id, email, name from credentials_tbl limit 1");

我错过了什么?

这是一个完整的例子,我希望它包含所有内容: (当使用Microsoft Visual Studio 2013运行时,我得到相同的错误)

// apply_test.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>

using namespace boost;

/* apply methods from https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments#answer-6454211 */

// ------------- UTILITY---------------
template<int...> struct index_tuple{};

template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;

template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
    typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};

template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
    typedef index_tuple<Indexes...> type;
};

template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};




// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------




template<class Ret, class... Args, int... Indexes >
Ret apply_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
    return pf(forward<Args>(get<Indexes>(tup))...);
}


template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), const tuple<Args...>&  tup)
{
    return apply_helper(pf, typename make_indexes<Args...>::type(),
        tuple<Args...>(tup));
}

template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), tuple<Args...>&&  tup)
{
    return apply_helper<Ret, Args...>(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}

/* end of apply methods */



/* class iSelectable */
template <typename...> struct iSelectable;

template<class...Ts>
class iSelectable
{
public:

    template<typename T>
    static T select(Ts&&...params)
    {
        return T(std::forward<Ts>(params)...);
    }

};


/* selector_helper */
template<typename TT, class...Ts>
struct selector_helper
{
    static TT doSelect(Ts&&... params)
    {
        return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
    }
};

class postgres_database_impl : private boost::noncopyable
    , public boost::enable_shared_from_this<postgres_database_impl>
{
public:

    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {

            boost::tuple<Ts...> tpl;            


            /* This is where my errors occur: */

            return apply(selector_helper<T, Ts...>::doSelect, tpl);

    }

};

typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;

class Database : private boost::noncopyable
{
public:


    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {
        return impl_->select_<T, Ts...>(sql);
    }



private:
    DatabaseImpl impl_;

};





class User : public iSelectable < int, std::string, std::string >
{
public:

    User(int id, const std::string& name, const std::string& surname)
    {
        /* only for testing purposes */
        std::cout << name << ", ";
        std::cout << name << ", ";
        std::cout << surname << std::endl;
    }
};


int _tmain(int argc, _TCHAR* argv[])
{

    Database db;
    User result = db.select_<User, int, std::string, std::string>
        ("select id, email, name from credentials_tbl limit 1");

    return 0;
}

1 个答案:

答案 0 :(得分:3)

无论问题的背景如何,我通常都希望selector_helper类型看起来更像:

template <typename...> struct iSelectable;

template<typename TT>
struct selector_helper
{
    template<class... Ts>
    static TT doSelect(Ts&&... params) {
        return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...);
    }
};

请注意嵌套template模板的额外select限定条件。如果select是一种类型(我们怎么知道),您可能也需要typenameWhere and why do I have to put the "template" and "typename" keywords?

<强>更新

查看更完整的示例,这正是问题所在。 do_select的模板参数是明确指定的:

return apply(selector_helper<T, Ts...>::doSelect, tpl);

这不会起作用,因为它会抑制模板参数推断,并且签名被强制

  

User (&)(int&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)

当然,虽然元组实际上是

  

boost::tuples::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ...>&

您可以看到针对Args...推断出的冲突类型。

我实际上会通过不那么具体来简化这个:

template <class Ret, class Tuple, class... Args, int... Indexes>
Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
    return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
}

template <class Ret, class Tuple, class... Args> 
Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
    return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
}

这已编译

<强> Live On Coliru

// apply_test.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/make_shared.hpp>

#define _TCHAR char
using namespace boost;

/* apply methods from
 * https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments#answer-6454211
 */

// ------------- UTILITY---------------
template <int...> struct index_tuple {};

template <int I, typename IndexTuple, typename... Types> struct make_indexes_impl;

template <int I, int... Indexes, typename T, typename... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...> {
    typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};

template <int I, int... Indexes> struct make_indexes_impl<I, index_tuple<Indexes...> > {
    typedef index_tuple<Indexes...> type;
};

template <typename... Types> struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> {};

// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
    template <class Ret, class Tuple, class... Args, int... Indexes>
    Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
        return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
    }

    template <class Ret, class Tuple, class... Args> 
    Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
        return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
    }

/* end of apply methods */

/* class iSelectable */
template <typename...> struct iSelectable;

template <class... Ts> struct iSelectable {
    template <typename T> static T select(Ts &&... params) { return T(std::forward<Ts>(params)...); }
};

/* selector_helper */
template <typename TT, class... Ts> struct selector_helper {
    static TT doSelect(Ts &&... params) { return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...); }
};

class postgres_database_impl : private boost::noncopyable,
                               public boost::enable_shared_from_this<postgres_database_impl> 
{
  public:
    template <typename T, typename... Ts> T select_(const std::string &sql) {
        boost::tuple<Ts...> tpl { -123, "fame", "something" };

        /* This is where my errors occur: */
        return apply(selector_helper<T, Ts...>::doSelect, tpl);
        return {123, "name", "something"};
    }
};

typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;

class Database : private boost::noncopyable {
  public:
    template <typename T, typename... Ts> T select_(const std::string &sql) { return impl_->select_<T, Ts...>(sql); }

  private:
    DatabaseImpl impl_ = boost::make_shared<postgres_database_impl>();
};

class User : public iSelectable<int, std::string, std::string> {
  public:
    User(int id, std::string name, std::string surname) 
        : id(id), name(std::move(name)), surname(std::move(surname)) {
    }

  private:
    int id;
    std::string name;
    std::string surname;

    friend std::ostream& operator << (std::ostream& os, User const& user) {
        return os << user.id << ", " << user.name << ", " << user.surname << "\n";
    }
};

int main() {
    Database db;
    User result =
        db.select_<User, int, std::string, std::string>("select id, email, name from credentials_tbl limit 1");

    std::cout << "Result: " << result << "\n";
}

输出:

Result: -123, fame, something

我认为我看到了进一步简化的大量机会,但说实话,我需要了解更多关于开始这一旅程的目标。